Mathy

Mathy.ai

A modern computer algebra system and reinforcement learning environments platform for interpretable symbolic mathematics.

Package version Join the chat at https://gitter.im/justindujardin/mathy

pip install mathy mathy_alpha_sm Successfully installed mathy, mathy_alpha_sm mathy simplify "2x + 1y^3 + 7b + 4x"

Documentation: https://mathy.ai

Source Code: https://github.com/justindujardin/mathy


Features

  • Computer Algebra System: Parse text into expression trees for manipulation and evaluation. Transform trees with user-defined rules that do not change the value of the expression.
  • Reinforcement learning: Train agents with machine learning in many environments with hyperparameters for controlling environment difficulties.
  • Custom Environments Extend built-in environments or author your own. Provide custom logic and values for custom actions, problems, timestep rewards, episode rewards, and win-conditions.
  • Visualize Expressions: Gain a deeper understanding of problem structures and rule transformations by visualizing binary trees in a compact layout with no branch overlaps.
  • Compute Friendly: Maybe we don't have to burn down the world with GPU compute all the time? Text-based environments can be small enough to train on a CPU while still having real-world value.
  • Free and Open Source: Mathy is and will always be free, because educational tools are too important to our world to be gated by money.
  • Python with Type Hints: typing hints are used everywhere in Mathy to help provide rich autocompletion and linting in modern IDEs.

Requirements

  • Python 3.6+
  • Tensorflow 2.0+

Installation

$ pip install mathy mathy_alpha_sm

Try It

Let's start by simplifying a polynomial problem using the CLI:

Simplify a Polynomial

$ mathy simplify "2x + 4 + 3x * 6"

This uses the pretrained mathy_alpha_sm model that we installed above.

The model is used to determine which intermediate steps to take in order to get to the desired solution.

The output will vary based on the model, but it might look like this:

mathy simplify "2x + 4 + 3x * 6"

Generate Input Problems

Mathy can generate lists of random problems. Rather than force users to generate solutions, Mathy uses environment-specific functions for determining when a problem is solved.

In this way users do not need to know the answer to a problem that is generated.

$ mathy problems poly

Train an A3C agent

Mathy has an A3C agent built-in that you can train from the CLI:

A3C uses multiple worker threads to train a shared model in a CPU-friendly setting.

$ mathy train a3c poly ./training/my_model

Train an MCTS agent

Mathy has a MCTS agent built-in that you can train from the CLI:

MCTS is a powerful tree search that is combined with a neural network to produce high quality actions.

$ mathy train zero poly ./training/my_model

Code It

Above we simplified a polynomial problem using the CLI, but what if the output steps had failed to find a solution?

Perhaps we put a subtraction between two like terms, like 4x + 3y - 2x

Recall that we can't move subtraction terms around with the commutative property, so how can Mathy solve this problem?

We can write custom code for Mathy in order to add features or correct issues.

In order to combine these terms, we need to convert the subtraction into an addition.

Remember that a subtraction like 4x + 3y - 2x can be restated as a "plus negative" like 4x + 3y + -2x to make it commutable.

Once we've restated the expression, we can now use the commutative property to swap the positions of 3y and -2x so we end up with 4x + -2x + 3y

Now the expression is in a state that Mathy's existing rules can handle the rest.

Create a Rule

To continue our 4x + 3y - 2x example, we'll write some code to convert the subtraction into an addition: 4x + -2x + 3y

Mathy uses the available set of rules (also referred to as actions) when transforming a problem.

To create a custom rule we extend the BaseRule class and define two main functions:

  • can_apply_to determines if a rule can be applied to an expression node.
  • apply_to applies the rule to a node and returns an expression change object.

Open Example In Colab

from mathy import (
    AddExpression,
    ExpressionParser,
    BaseRule,
    NegateExpression,
    SubtractExpression,
)


class PlusNegationRule(BaseRule):
    """Convert subtract operators to plus negative to allow commuting"""

    @property
    def name(self) -> str:
        return "Plus Negation"

    @property
    def code(self) -> str:
        return "PN"

    def can_apply_to(self, node) -> bool:
        is_sub = isinstance(node, SubtractExpression)
        is_parent_add = isinstance(node.parent, AddExpression)
        return is_sub and (node.parent is None or is_parent_add)

    def apply_to(self, node):
        change = super().apply_to(node)
        change.save_parent()  # connect result to node.parent
        result = AddExpression(node.left, NegateExpression(node.right))
        result.set_changed()  # mark this node as changed for visualization
        return change.done(result)


parser = ExpressionParser()
expression = parser.parse("4x - 2x")
rule = PlusNegationRule()

# Find a node and apply the rule
applicable_nodes = rule.find_nodes(expression)
assert len(applicable_nodes) == 1
assert applicable_nodes[0] is not None

# Verify the expected change
change = rule.apply_to(applicable_nodes[0])
assert str(change.result) == "4x + -2x"

Use it during training

Now that we've created a custom rule for converting subtract nodes into "plus negative" ones, we need Mathy to use it while training.

We do this with custom environment arguments when using the A3C Agent and the Poly Simplify environment.

All together it looks like:

Open Example In Colab

#!pip install gym
import os
import shutil
import tempfile

import gym

from mathy import (
    AddExpression,
    BaseRule,
    MathExpression,
    ExpressionParser,
    MathyEnv,
    NegateExpression,
    SubtractExpression,
)
from mathy.envs import PolySimplify
from mathy.agents.a3c import A3CAgent, A3CConfig
from mathy.cli import setup_tf_env


class PlusNegationRule(BaseRule):
    """Convert subtract operators to plus negative to allow commuting"""

    @property
    def name(self) -> str:
        return "Plus Negation"

    @property
    def code(self) -> str:
        return "PN"

    def can_apply_to(self, node: MathExpression) -> bool:
        is_sub = isinstance(node, SubtractExpression)
        is_parent_add = isinstance(node.parent, AddExpression)
        return is_sub and (node.parent is None or is_parent_add)

    def apply_to(self, node: MathExpression):
        change = super().apply_to(node)
        change.save_parent()  # connect result to node.parent
        result = AddExpression(node.left, NegateExpression(node.right))
        result.set_changed()  # mark this node as changed for visualization
        return change.done(result)


# Quiet tensorflow debug outputs
setup_tf_env()
# Train in a temporary folder
model_folder = tempfile.mkdtemp()
# Add an instance of our new rule to the built-int environment rules
all_rules = MathyEnv.core_rules() + [PlusNegationRule()]
# Specify a set of operators to choose from when generating poly simplify problems
env_args = {"ops": ["+", "-"], "rules": all_rules}
# Configure and launch the A3C agent training
args = A3CConfig(
    max_eps=1,
    num_workers=1,
    print_training=True,
    topics=["poly"],
    model_dir=model_folder,
)
A3CAgent(args, env_extra=env_args).train()
# Comment this out to keep your model
shutil.rmtree(model_folder)

Congratulations, you've extended Mathy and begun training a new model with your custom action!

Become a Contributor

Building new actions and problem sets are great ways to contribute to Mathy.

By contributing improvements to Mathy, we help ourselves better understand Math and Programming.

We also create examples for others around the world that are trying to get help with Math or learn Programming!

Contributors

Mathy wouldn't be possible without the wonderful contributions of the following people:

This project follows the all-contributors specification. Contributions of any kind welcome!