Skip to content

Instantly share code, notes, and snippets.

@kharysharpe
Last active August 29, 2016 13:29
Show Gist options
  • Save kharysharpe/0f8e9e6d7727a038e19fad8ec1f96c0e to your computer and use it in GitHub Desktop.
Save kharysharpe/0f8e9e6d7727a038e19fad8ec1f96c0e to your computer and use it in GitHub Desktop.
HOA Math - Solves interconnected expressions

Solves a series of related expressions

a = 1

b = a + 1

c = b * 2

d = a + b

Usage:

$solver = new Solver();
$solver->addValue('a', 1);

$solver->addFormula('b', 'a + 1');
$solver->addFormula('c', 'b * 2');
$solver->addFormula('d', 'a + c');

$solver->solve();

var_dump($solver->getResults());

Outputs:

array (size=4)
  'a' => int 1
  'b' => float 2
  'c' => float 4
  'd' => float 5

Solver class:

class Solver
{
	protected $values = [];
	protected $formulas = [];
	protected $answers = [];
	protected $functions = [];

	function addValue($name, $value)
	{
	    if (isset($this->values[$name])) {
	        throw new \Exception("Value '{$name}' already declared cannot redeclare/overwrite value");
        }

        if (isset($this->formulas[$name])) {
            throw new \Exception("Formula already exists with the name '{$name}'. Can you give it another name?");
        }


		$this->values[$name] = $value;
	}

	//Used internally to add answers back to the value stack
    private function pushValue($name, $value)
    {
        if (isset($this->values[$name])) {
            throw new \Exception("Value '{$name}' already declared cannot redeclare/overwrite value");
        }

        $this->values[$name] = $value;
    }

	function addFormula($name, $formula)
	{
        if (isset($this->formulas[$name])) {
            throw new \Exception("Formula '{$name}' already declared cannot redeclare/overwrite formula");
        }

        if (isset($this->values[$name])) {
            throw new \Exception("Value already exists with the name '{$name}'. Can you give it another name?");
        }


		$this->formulas[$name] = $formula;
	}

	function addFunction($name, callable $closure)
	{
		$this->functions[$name] = $closure;
	}



	function getVisitor()
	{
		$instance = new Hoa\Math\Visitor\Arithmetic(); 

		foreach ($this->values as $key => $value) {

		    $instance->addVariable($key, function() use ($value) {
		        return $value;
		    });
		}

		foreach ($this->functions as $key => $closure) {
			
			$instance->addFunction($key, $closure);
		}

		return $instance;
	}

	function solve()
	{
		foreach ($this->formulas as $name => $formula) {

			$compiler = Hoa\Compiler\Llk::load(new Hoa\File\Read('hoa://Library/Math/Arithmetic.pp'));

			$visitor = $this->getVisitor();

			$ast = $compiler->parse($formula);

			$answer = $visitor->visit($ast);

			$this->answers[$name] = $answer;

			$this->pushValue($name, $answer);
    
		}
	}

	function getResults()
	{
		$result = array_merge($this->values, $this->answers);

		return $result;
	}

    function getAnswers()
    {
        return $this->answers;
    }

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment