# 2d-algebra

Library for building expressions and computing derivatives

## Usage no npm install needed!

``````<script type="module">
import dAlgebra from 'https://cdn.skypack.dev/2d-algebra';
</script>``````

# 2D Algebra Typescript Module

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

## 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());
``````

## 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` or `Expression`.

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
``````

## 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.