## README

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

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 `times(b^-1)` |

toThe(n) | raises the top term by the `number` n. |

squared() | equivalent to `toThe(2)` |

sin() | replaces the top term with the sin(a) |

cos() | replaces the top term with the cos(a) |

tan() | equivalent to `sin(a).dividedBy(cos(a))` |

eq(b) | equivalent to `minus(b).squared()` |

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, Expression>) | substitute one or more variables with expressions 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. |

`(`

or `)`

Why no parentheses? 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

- fork and clone the git repository
- 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.

- If making changes to the
- run
`yarn test`

. if they fail goto step 2 - push changes to your fork
- 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.