Skip to content

Commit

Permalink
Merge pull request #15 from mathy/feat/docs
Browse files Browse the repository at this point in the history
Feat/docs
  • Loading branch information
justindujardin authored Dec 15, 2023
2 parents bc0fb87 + 6ec236e commit de65e6b
Show file tree
Hide file tree
Showing 87 changed files with 4,771 additions and 25 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ jobs:
- name: Build Packages
run: sh tools/build.sh
- name: Test Packages
run: sh tools/test.sh
run: sh tools/test_all.sh
- name: Update API Docs
run: sh tools/docs.sh
- name: Report Code Coverage
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
Expand Down
Empty file added CHANGELOG.md
Empty file.
8 changes: 4 additions & 4 deletions mathy_core/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
MathTypeKeysMax = max(MathTypeKeys.values()) + 1


class MathExpression(BinaryTreeNode):
class MathExpression(BinaryTreeNode["MathExpression"]):
"""Math tree node with helpers for manipulating expressions.
`mathy:x+y=z`
Expand Down Expand Up @@ -117,7 +117,7 @@ def visit_fn(
def with_color(self, text: str, style: str = "bright") -> str:
"""Render a string that is colored if something has changed"""
if self._rendering_change is True and self._changed is True:
return color(text, fore=self.color, style=style)
return f"{color(text, fore=self.color, style=style)}"
return text

def add_class(self, classes: Union[List[str], str]) -> "MathExpression":
Expand Down Expand Up @@ -147,7 +147,7 @@ def visit_fn(

def to_list(self, visit: str = "preorder") -> List["MathExpression"]:
"""Convert this node hierarchy into a list."""
results = []
results: List[MathExpression] = []

def visit_fn(
node: MathExpression, depth: int, data: Any
Expand Down Expand Up @@ -688,7 +688,7 @@ def clone(self) -> "ConstantExpression": # type:ignore[override]
result.value = self.value
return result # type:ignore

def evaluate(self, _context: Optional[Dict[str, NumberType]] = None) -> NumberType:
def evaluate(self, context: Optional[Dict[str, NumberType]] = None) -> NumberType:
assert self.value is not None
return self.value

Expand Down
4 changes: 4 additions & 0 deletions mathy_core/layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

Mathy uses the Tidier algorithm to create visual tree layouts for helping understand and interpret complex node trees.

`mathy:(28 + 1x)(17x - 2y)`
17 changes: 17 additions & 0 deletions mathy_core/parser.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Mathy parses [token arrays](./tokenizer) into inspectable, transformable, visualizable symbolic trees.

## Motivation

A Token array verifies that text maps to some known symbols, not that they are a correct ordering that produces a valid mathematical expression. The mathy Parser class converts tokens into a tree while also validating that the tree follows the expected Order of Operations.

## Examples

To help better understand what the parser does, consider a few examples of expressions and their visualized trees:

| Text | Tree |
| --------------------- | --------------------------- |
| `4x` | `mathy:4x` |
| `4x / 2y^7` | `mathy:4x/2y^7` |
| `4x + (1/3)y + 7x` | `mathy:4x+ (1/3)y + 7x` |
| `4x + 1/3y + 7x` | `mathy:4x+ 1/3y + 7x` |
| `(28 + 1j)(17j + 2y)` | `mathy:(28 + 1j)(17j + 2y)` |
44 changes: 44 additions & 0 deletions mathy_core/rules/associative_swap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
The `Associative Property` of numbers says that we can re-group two `addition` or `multiplication` terms so that one is evaluated before the other without changing the value of the expression.

The formulation of this property is the same for addition and multiplication:

- Addition `(a + b) + c = a + (b + c)`
- Multiplication `(a * b) * c = a * (b * c)`

!!! note

Interestingly, applying the associative property of numbers to a binary expression tree is a standard tree operation called a "node rotation."

### Transformations

#### Addition

```
(a + b) + c = a + (b + c)
(y) + + (x)
/ \ / \
/ \ / \
(x) + c -> a + (y)
/ \ / \
/ \ / \
a b b c
```

#### Multiplication

```
(a * b) * c = a * (b * c)
(x) * * (y)
/ \ / \
/ \ / \
(y) * c <- a * (x)
/ \ / \
/ \ / \
a b b c
```

### Examples

`rule_tests:associative_swap`
40 changes: 40 additions & 0 deletions mathy_core/rules/commutative_swap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
The `Commutative Property` of numbers says that we can re-order two `addition` or `multiplication` terms so that one occurs before the other in the expression without changing the value of the expression.

The formulation of this property is the same for addition and multiplication:

- Addition `a + b = b + a`
- Multiplication `a * b = b * a`

The commutative property is used for re-arranging the order of parts of an expression and is, as such, very important for working with mathematical expressions.

### Transformations

Given a common parent node, this rule switches the order of the children of that node. It can only be applied to addition or multiplication nodes.

#### Addition

`a + b = b + a`

```
+ +
/ \ / \
/ \ -> / \
/ \ / \
a b b a
```

#### Multiplication

`a * b = b * a`

```
* *
/ \ / \
/ \ -> / \
/ \ / \
a b b a
```

### Examples

`rule_tests:commutative_swap`
37 changes: 37 additions & 0 deletions mathy_core/rules/constants_simplify.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
The `Constant Arithmetic` rule transforms an expression tree by combining two constant values separated by a binary operation like `addition` or `division`.

### Transformations

#### Two Constants

The most uncomplicated transform is to evaluate two constants that are siblings.

- `(4 * 2) + 3` = `8 + 3`

#### Sibling Skipping

The constant simplify rule can simplify constants across a sibling when the sibling is a variable chunk, and the constants are commutatively connected.

For example, `2x * 8` can be transformed into `16x` because the constants are connected through a multiplication chain that allows [commuting](./commutative_property).

We can see this by taking a look at the trees for `2x * 8` and `2 * 8 * x` and recalling that the commutative property says `a * b = b * a`:

| Satisfying the Commutative Property | |
| :---------------------------------: | :---------------- |
| `mathy:2x * 8` | `mathy:2 * 8 * x` |

We can see that the tree structure has been flipped but that multiplication nodes still connect the same variables and constants, so the value of the expression remains unchanged.

#### Alternate Tree Forms

Math trees can be represented in many different equivalent forms, so mathy supports these unnatural groupings to make this rule applicable to more nodes in the tree.

- `5 * (8h * t)` = `40h * t`
- `(7 * 10y^3) * x` = `70y^3 * x`
- `(7q * 10y^3) * x` = `(70q * y^3) * x`
- `792z^4 * 490f * q^3` = `388080z^4 * f * q^3`
- `(u^3 * 36c^6) * 7u^3` = `u^3 * 252c^6 * u^3`

### Examples

`rule_tests:constants_simplify`
31 changes: 31 additions & 0 deletions mathy_core/rules/distributive_factor_out.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
The `Distributive Property` of numbers says that we can factor out common values from terms connected with an addition operator.

This rule is expressed by the equation `ab + ac = a(b + c)`

!!! note

This is a core transformation used in combining like terms, though we usually skip over it mentally because humans are pretty intelligent.

Consider that the `9y + 9y` example from above becomes `(9 + 9) * y`. If you apply a constant simplification rule, you end up with `18y`, which results from combining the two like `y` terms.

### Transformations

Given a common parent node, this rule extracts the common value from both sides, leaving an addition and a multiplication.

#### Addition

`ab + ac = a(b + c)`

```
+ *
/ \ / \
/ \ / \
/ \ -> / \
* * a +
/ \ / \ / \
a b a c b c
```

### Examples

`rule_tests:distributive_factor_out`
26 changes: 26 additions & 0 deletions mathy_core/rules/distributive_multiply_across.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
The `Distributive Property` can distribute multiplication across grouped terms. This has the effect of removing a grouping and can expose the terms that were inside for further simplification depending on the problem type.

This rule is expressed by the equation `a(b + c) = ab + ac`

### Transformations

Given a multiplication of `a` and `(b + c)`, this rule distributes `a` across `b` and `c`, leaving only the simpler form of `ab` and `ac`.

#### Addition

`a(b + c) = ab + ac`

```
+
* / \
/ \ / \
/ \ / \
a + -> * *
/ \ / \ / \
/ \ / \ / \
b c a b a c
```

### Examples

`rule_tests:distributive_multiply_across`
61 changes: 61 additions & 0 deletions mathy_core/rules/variable_multiplication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
The `Variable Multiplication` rule restates `x^b * x^d` as `x^(b + d)`, which isolates the exponents attached to the variables so they can be combined.

!!! note

This rule can only be applied when the nodes have matching variable bases. This means that `x * y` cannot be combined, but `x * x` can be.

### Transformations

Both implicit and explicit variable powers are recognized in this transformation.

!!! info "Help Wanted"

The current variable multiply rule leaves out a case where there is a power
raised to another power, they can be combined by multiplying the exponents
together.

For example: `x^(2^2) = x^4`

If you would like to help out with by updating this rule [open an issue here](https://github.com/justindujardin/mathy/issues/new?title=VariableMultiplyRaisePowerToPower){target=\_blank}

#### Explicit powers

In the simplest case, both variables have explicit exponents.

Examples: `x^b * x^d = x^(b+d)`

- `42x^2 * x^3` becomes `42x^(2 + 3)`
- `x^1 * x^7` becomes `x^(1 + 8)`

```
*
/ \
/ \ ^
/ \ = / \
^ ^ x +
/ \ / \ / \
x b x d b d
```

#### Implicit powers

When not explicitly stated, a variable has an implicit power of being raised to the 1, and this form is identified.

Examples: `x * x^d = x^(1 + d)`

- `42x * x^3` becomes `42x^(1 + 3)`
- `x * x` becomes `x^(1 + 1)`

```
*
/ \
/ \ ^
/ \ = / \
x ^ x +
/ \ / \
x d 1 d
```

### Examples

`rule_tests:variable_multiply`
32 changes: 32 additions & 0 deletions mathy_core/tokenizer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## Motivation

We first need an intermediate representation to parse math text into tree structures that encode the Order of Operations of the input. Specifically, we want to build a list of text characters corresponding to relevant `tokens` for a math expression. That is what the tokenizer does.

The tokenization process treats the input string as an array of characters, iterating over them to produce a list of tokens with `type`/`value` properties. While building the collection, the tokenizer also optionally discards extra whitespace characters.

## Visual Example

For example, consider the input text `8 - (2 + 4)` and its token representation.

`tokens:8 - (2 + 4)`

- The top row contains the token value.
- The bottom row includes the integer type of the token represented by the value.

## Code Example

Simple tokenization only requires a few lines of code:

```Python

{!./snippets/cas/tokenizer_tokenize.py!}

```

## Conceptual Example

To better understand the tokenizer, let's build a tokens array manually then compare it to the tokenizer outputs:

```Python
{!./snippets/cas/tokenizer_manual.py!}
```
Loading

0 comments on commit de65e6b

Please sign in to comment.