Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/add solution class #11

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
/nbproject
/tests/output
/composer.lock
/.idea
/.phpunit.result.cache
57 changes: 56 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,59 @@ Enjoy.
Conventions
-----------

Please name your variables as **x<n>** where *<n>* is a natural number (see [example.php](https://github.com/uestla/Simplex-Calculator/blob/master/example.php) for details).
Please name your variables as **x<n>** where *<n>* is a natural number (
see [example.php](https://github.com/uestla/Simplex-Calculator/blob/master/example.php) for details).


Using LinearProgram class
-------------------------

Using `\Simplex\Formulation\LinearProgram` you can formulate linear program solution.

For example let's assume, that we have given linear problem:

> z = 2x1 + x2

with constraints:
> x1 + x2 >= 2
>
> x1 - x2 = 0
>
> x1 - x2 >= -4

that we can describe in following way:

```php
use \Simplex\Formulation\LinearProgram;
use \Simplex\Formulation\Formula;
use \Simplex\Formulation\GreaterOrEqual;
use \Simplex\Formulation\Equal;

$program = new LinearProgram(
new Formula(2, 1),
[
new GreaterOrEqual(new Formula(1, 1), 2),
new Equal(new Formula(1, -1), 0),
new GreaterOrEqual(new Formula(1, -2), -4),
]
);
```

Now we can take maximum solution with only:

```php
$program->getMax(); // return 12
```

And optimized parameters:

```php
$solution = $program->getSolutionFormula();
// returns new Formula(4, 4, 6, 0);

$solution->getParam('x1'); // 4
$solution->getParam(1); // the same as upper 4
```

see [example_simplified.php](https://github.com/uestla/Simplex-Calculator/blob/master/example_simplified.php) for
details.
28 changes: 28 additions & 0 deletions Simplex/Formulation/Constraint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Simplex\Formulation;

abstract class Constraint
{
protected Formula $formula;
protected int $constraint;

/**
* GreaterOrEqual constructor.
*/
public function __construct(Formula $formula, int $constraint)
{
$this->formula = $formula;
$this->constraint = $constraint;
}

public function getFormula(): Formula
{
return $this->formula;
}

public function getConstraint(): int
{
return $this->constraint;
}
}
7 changes: 7 additions & 0 deletions Simplex/Formulation/Equal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Simplex\Formulation;

final class Equal extends Constraint
{
}
65 changes: 65 additions & 0 deletions Simplex/Formulation/Formula.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace Simplex\Formulation;

/**
* Class Formula
*
* Formula class is used for write formula of a function.
*
* For example:
* y = 10x1 + 2x2 - x3 + 3x5
*
* Then instantiation should be:
* new Formula(10, 2, -1, 0, 3)
*
* @package Simplex\Formalization
*/
class Formula
{
private array $coefficients;

/**
* Formula constructor.
*/
public function __construct(...$coefficients)
{
if (is_array($coefficients[0])) {
$coefficients = $coefficients[0];
}

// not keys in case of assoc
$i = 0;

foreach ($coefficients as $coefficient) {
if (!is_numeric($coefficient)) {
throw new \InvalidArgumentException("Construct \$coefficient params have to be number");
}

$this->coefficients['x' . ++$i] = $coefficient;
}
}

public function getCoefficients(): array
{
return $this->coefficients;
}

public function getSize(): int
{
return count($this->coefficients);
}

public function getParam(string $variable): float
{
if (is_numeric($variable)) {
$variable = 'x' . $variable;
}

if (!array_key_exists($variable, $this->coefficients)) {
throw new \InvalidArgumentException('Variable ' . $variable . 'is not exists');
}

return $this->coefficients[$variable];
}
}
7 changes: 7 additions & 0 deletions Simplex/Formulation/GreaterOrEqual.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Simplex\Formulation;

final class GreaterOrEqual extends Constraint
{
}
89 changes: 89 additions & 0 deletions Simplex/Formulation/LinearProgram.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

namespace Simplex\Formulation;

use Simplex\Func;
use Simplex\Restriction;
use Simplex\Solution;
use Simplex\Solver;
use Simplex\Task;
use Simplex\VariableSet;

class LinearProgram
{
protected Formula $goal;
protected array $constraints;
protected Task $task;
protected Solution $solution;

/**
* LinearProgram constructor.
*/
public function __construct(Formula $goal, array $constraints)
{
$this->validate($goal, $constraints);

$this->goal = $goal;
$this->constraints = $constraints;

$this->makeTask();
$this->solution = Solution::build($this->task);
}

private function validate(Formula $goal, array $constraints): void
{
foreach ($constraints as $constraint) {
if (!$constraint instanceof Constraint) {
throw new \InvalidArgumentException("All \$constraints have to be instance of \Simplex\Constraint");
}

if ($constraint->getFormula()->getSize() !== $goal->getSize()) {
throw new \OutOfBoundsException("Number of parameters are not the same for each formula");
}
}
}

private function makeTask(): void
{
$z = new Func($this->goal->getCoefficients());
$this->task = new Task($z);

/** @var Constraint $constraint */
foreach ($this->constraints as $constraint) {
$restriction = [
GreaterOrEqual::class => Restriction::TYPE_GOE,
LowerOrEqual::class => Restriction::TYPE_LOE,
Equal::class => Restriction::TYPE_EQ,
][get_class($constraint)];

$this->task->addRestriction(
new Restriction(
$constraint->getFormula()->getCoefficients(),
$restriction,
$constraint->getConstraint()
)
);
}
}

public function getSolution(): Solution
{
return $this->solution;
}

public function getOptimizedParams(): array
{
return $this->solution->getSolutionParams();
}

public function getMax(): float
{
return $this->solution->getMax();
}

public function getSolutionFormula(): Formula
{
return new Formula($this->solution->getSolutionParams());
}

}
7 changes: 7 additions & 0 deletions Simplex/Formulation/LowerOrEqual.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Simplex\Formulation;

final class LowerOrEqual extends Constraint
{
}
Loading