npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

2d-algebra

v4.0.0

Published

Library for building expressions and computing derivatives

Downloads

53

Readme

2D Algebra Typescript Module

A library for programatically building up large systems of equations for numerical analysis.

NPM Version Downloads Stats

Technologies

Project is created with:

  • Typescript version: 3.6.2
  • Node version: 12.10.0
  • No external dependencies

Setup

To use this library

npm install 2d-algebra yarn add 2d-algebra

Then in your code you can import and use the expression(...) function to fluently build expressions.

import expression from "2d-algebra";

const m = 3; // slope
const b = 4; // point
const x = Symbol("x");
const y = Symbol(); // naming your symbols is optional
const line = expression(m).times(x).plus(b).eq(y);

const solution = new Map([
  [x, 7483],
  [y, 22453],
]);

const err = line.eval(solution);
// err === 0

const dxLine = line.derivative(x);
const xSlope = dxLine.eval(solution);
// xSlope === 0

const dyLine = line.derivative(y);
const ySlope = dyLine.eval(solution);
// ySlope === 0

const dx2Line = dxLine.derivative(x);
const xCup = dx2Line.eval(solution);
// xCup > 0

const dy2Line = dyLine.derivative(y);
const yCup = dx2Line.eval(solution);
// yCup > 0

// https://en.wikipedia.org/wiki/Second_partial_derivative_test
const dxdyLine = dxLine.derivative(y);
const hessianDet = dx2Line.times(dy2Line).minus(dxdyLine.squared());
const xySaddle = hessianDet.eval(solution);
// xySaddle === 0

API

Creating a new Expression is a easy as starting it off with the first symbol or number.

const one = expression(1).eval(new Map())

From there you can use the following methods to additional complexity. All methods do not change the existing Expression but return a new Expression (AKA immutable). The b argument must be either a symbol, number, Expression or Matrix.

| Method | Description | | ------------ | ---------------------------------------------------- | | plus(b) | add the top term to b and simplifies | | minus(b) | equivalent to plus(-b) | | times(b) | multiplies the top term with b and simplifies | | dividedBy(b) | equivalent to push(b).toThe(-1).times() | | toThe(n) | raises the top term by the number n. | | squared() | equivalent to toThe(2) | | sin() | replaces the top term with the sine | | cos() | replaces the top term with the cossine | | tan() | equivalent to this.sin().push(this).cos().divide() | | eq(b) | equivalent to minus(b).squared() | | abs() | replaces the top term with the absolution value |

Once the expression is complete you can use the following methods

| Method | Description | | ------------------------- | ----------------------------------------------------------------------------------- | | eval(Map<symbol, number>) | fully evaluate the expression. throw error if not all of the symbols are defined. | | apply(Map<symbol, Term>) | substitute one or more variables with different term and return the new expression. | | derivative(symbol) | compute the partial derivative with respect to one symbol. | | toString() | makes a ASCII art tree diagram of the expression tree. |

Why no parentheses? ( or )

At this point you've probably run into an expression where you only want to apply the next times or squared to only part of what comes before. For example the unit (of radius 1) circle one might mistakenly define it as:

const r = 1;
const x = Symbol();
const y = Symbol();

// EXAMPLE OF HOW TO DO IT WRONG
const circle = expression(x)
  .squared() //   x^2
  .plus(y) //   x^2 + y
  .squared() //  (x^2 + y)^2
  .eq(r) //  (x^2 + y)^2 - r)^2
  .squared(); // ((x^2 + y)^2 - r)^2)^2

Would produce ((x^2 + y)^2 - r)^2)^2. When I would have expected (x^2 + y^2 - r^2)^2. Notice how in the wrong expression each application of the squared() applied to the whole of expression defined up to that point. To fix this I'll introduce the push(b) method that starts a new mini expression separate from what has been defined so far. When push is used new zero argument versions of plus(), minus(), times(), divide(), and eq() are available to cause the two mini expressions to be merged into one again.

The corrected code now looks like:

const circle = expression(x)
  .squared() //  x^2
  .push(y) //  x^2 | y   <---- y here is separate from x^2
  .squared() //  x^2 | y^2 <---- now that y is squared on its own
  .plus() //  x^2 + y^2 <---- merge y^2 by adding it to x^2
  .push(r) //  x^2 + y^2 | r
  .squared() //  x^2 + y^2 | r^2
  .eq(); // (x^2 + y^2 - r^2)^2

Matrices

Matrices of expressions are also supported. The first call to matrix() creates a row matrix and subsequent calls creates a new matrix with additional row.

const M = matrix(1, 2, 3);
const N = M(4, 5, 6);

M !== N;
M.toString() === "[1, 2, 3]";
N.toString() === "[1, 2, 3; 4, 5, 6]";

Once the matrix is built to your needs you can chain following methods.

| Method | Description | | ------------ | -------------------------------------------- | | plus(b) | adds b to all elements | | minus(b) | subtracts b from all elements | | times(b) | multiplies b (scalar) to all elements | | times(b) | multiplies b (matrix) dot product | | dividedBy(b) | divides all elements by b (scalar) | | dividedBy(b) | equivalent to .times(b.inverse()) (matrix) | | inverse() | if possible returns the inverse matrix | | eq(b) | equivalent to minus(b).squared() (scalar) |

const theta = Symbol("Θ");
const x = Symbol("x");
const y = Symbol("y");

// 2D translate
const translate = matrix(1, 0, x)(0, 1, y)(0, 0, 1);

// 2D rotation
const rotate = matrix(cos(theta), sin(theta).times(-1), 0)(
  sin(theta),
  cos(theta),
  0
)(0, 0, 1);

// take the inverse of the translation to get the shape to the origin
// https://en.wikipedia.org/wiki/Matrix_similarity

// 2D rotation around arbitrary point
// 1) move to origin
// 2) rotate around origin
// 3) move back
const output = translate.times(rotate).dividedBy(translate);

// output =
//   [cos(Θ), -sin(Θ),  x*cos(Θ) - y*sin(Θ) + x;
//    sin(Θ),  cos(Θ), -x*sin(Θ) - y*cos(Θ) + y;
//         0,       0,                        1]

Contributing

To submit changes to the project

  1. fork and clone the git repository
  2. make changes to the tests and source.
    • If making changes to the Expression class make sure matching changes are made to ExpressionStack.
    • Changes to simplification logic can be quite tricky with all the symbiotic recursion.
  3. run yarn test. if they fail goto step 2
  4. push changes to your fork
  5. submit pull request

Other ussful commands

  • yarn compile: compile the typescript code to POJS
  • yarn test: run unit tests once.
  • yarn watch: continuously run unit tests.