diff --git a/WCS/os.php b/WCS/os.php index 10cba79..3fda891 100644 --- a/WCS/os.php +++ b/WCS/os.php @@ -11,11 +11,11 @@ class OS { private $osil=NULL; private $osrl=NULL; private $var=array(); // Reverse IDX mapping ($idx->$name). - private $value=NULL; // Solution value. - private $solution=NULL; + public $value=NULL; // Solution value. + public $solution=NULL; - function __construct($maxOrMin='min') { + function __construct($maxOrMin='max') { $osil=new \SimpleXMLElement(''); $osil->addChild('instanceHeader')->addChild('name',php_uname('n').' '.date('c')); $data=$osil->addChild('instanceData'); diff --git a/Web/.gitignore b/Web/.gitignore new file mode 100644 index 0000000..34f73a0 --- /dev/null +++ b/Web/.gitignore @@ -0,0 +1,2 @@ +/solution.xml +/test.xml diff --git a/Web/E1bInClass.php b/Web/E1bInClass.php new file mode 100644 index 0000000..ec5f406 --- /dev/null +++ b/Web/E1bInClass.php @@ -0,0 +1,209 @@ +demand=$dem; + $this->profit=$p; + } +} + +$departmentDem["$departments[0]"]=new Department(600,20); +$departmentDem["$departments[1]"]=new Department(200,30); +$departmentDem["$departments[2]"]=new Department(300,40); +$departmentDem["$departments[3]"]=new Department(100,25); +$departmentDem["$departments[4]"]=new Department(300,25); + + +class Supplier{ + public $capacity; + public $pCost; + + function __construct($c,$pc){ + $this->capacity=$c; + $this->pCost=$pc; + } +} + +$supplierCap["$suppliers[0]"] = new Supplier(600,10); +$supplierCap["$suppliers[1]"] = new Supplier(300,14); +$supplierCap["$suppliers[2]"] = new Supplier(200,40); +$supplierCap["$suppliers[3]"] = new Supplier(500,11); + + +//print_r($departmentDem); +//print_r($supplierCap); + +class Distance{ + + public $distance; + function __construct($dist){ + $this->distance=$dist; + } +} + + +$distanceMatrix["$suppliers[0]-$departments[0]"]=new Distance(2); +$distanceMatrix["$suppliers[0]-$departments[1]"]=new Distance(3); +$distanceMatrix["$suppliers[0]-$departments[2]"]=new Distance(3); +$distanceMatrix["$suppliers[0]-$departments[3]"]=new Distance(3); +$distanceMatrix["$suppliers[0]-$departments[4]"]=new Distance(3); + +$distanceMatrix["$suppliers[1]-$departments[0]"]=new Distance(5); +$distanceMatrix["$suppliers[1]-$departments[1]"]=new Distance(2); +$distanceMatrix["$suppliers[1]-$departments[2]"]=new Distance(4); +$distanceMatrix["$suppliers[1]-$departments[3]"]=new Distance(4); +$distanceMatrix["$suppliers[1]-$departments[4]"]=new Distance(2); + +$distanceMatrix["$suppliers[2]-$departments[0]"]=new Distance(3); +$distanceMatrix["$suppliers[2]-$departments[1]"]=new Distance(2); +$distanceMatrix["$suppliers[2]-$departments[2]"]=new Distance(8); +$distanceMatrix["$suppliers[2]-$departments[3]"]=new Distance(2); +$distanceMatrix["$suppliers[2]-$departments[4]"]=new Distance(2); + +$distanceMatrix["$suppliers[3]-$departments[0]"]=new Distance(3); +$distanceMatrix["$suppliers[3]-$departments[1]"]=new Distance(2); +$distanceMatrix["$suppliers[3]-$departments[2]"]=new Distance(4); +$distanceMatrix["$suppliers[3]-$departments[3]"]=new Distance(2); +$distanceMatrix["$suppliers[3]-$departments[4]"]=new Distance(2); + + +//print_r($distanceMatrix); + +$os=new \WebIS\OS; +//assertTrue($os->solve()); + + +//echo $distanceMatrix["S1-D1"]->distance; + +//setting up the objective function +foreach($suppliers as $s){ + foreach($departments as $d){ + $var="${s}-${d}"; + $os->addVariable($var); + $os->addObjCoef($var,$departmentDem[$d]->profit - $distanceMatrix["$var"]->distance - $supplierCap[$s]->pCost); + //print $departmentDem[$d]->profit - $distanceMatrix["$var"]->distance - $supplierCap[$s]->pCost; + print "\n"; + //print "$var\n"; + +} +} + +//adding the constraints + + +$x=0; +foreach($supplierCap as $s ){ + $x+=1; + $ub = $s->capacity; + //print $ub; + //print $s; + $os->addConstraint(NULL,$ub); + foreach($departments as $key){ + $currentKey="S$x-${key}"; + $os->addConstraintCoef($currentKey,1); + //print $currentKey; + } +} + +$x=0; +foreach($departmentDem as $d ){ + $x+=1; + $lb = $d->demand; + $os->addConstraint($lb,NULL); + foreach($suppliers as $k){ + $currKey="${k}-D$x"; + $os->addConstraintCoef($currKey,1); + //print $currentKey; + } +} + +$x=0; +foreach($supplierCap as $s ){ + $x+=1; + $lb = 100; + $os->addConstraint($lb,NULL); + foreach($departments as $key){ + $currentKey="S$x-${key}"; + $os->addConstraintCoef($currentKey,1); + //print $currentKey; + } +} + + +$os->solve(); + + + +$x=0; +$a=0; +foreach($supplierCap as $s ){ + $x+=1; + foreach($departments as $key){ + $currentKey="S$x-${key}"; + //print_r($os->getVariable($currentKey)); + //print $currentKey; + print "\n"; + $currentRevenue = $os->getVariable($currentKey); + $revenue["$suppliers[$a]"]=$revenue["$suppliers[$a]"]+$currentRevenue; + } + $a+=1; +} + +//print_r($revenue); + +$x=0; +foreach($departments as $key){ + $a=0; + + foreach($supplierCap as $s ){ + $a+=1; + $currentKey="S$a-${key}"; + //print_r($os->getVariable($currentKey)); + //print $currentKey; + $currentProfit = $os->getVariable($currentKey); + $profit["$departments[$x]"]=$profit["$departments[$x]"]+$currentProfit; + + } + $x+=1; +} + + + +//print_r($totalProfit); +//print_r($profit); + +//print_r($os->value); + + + +?> + diff --git a/Web/E1bInClassOutput.php b/Web/E1bInClassOutput.php new file mode 100644 index 0000000..3cc15f9 --- /dev/null +++ b/Web/E1bInClassOutput.php @@ -0,0 +1,124 @@ + + + + + + +Exam 1 + + +

EXAM InClass INPUT AND OUTPUT

+

+

+The maximum profit = $$os->solution"; + +//shipping matrix +echo "

Shipping Matrix"; +echo ""; +} +foreach($departments as $d){ + echo ""; + } + echo "\n"; +} +echo ""; +echo "\n
\n"; + +foreach($suppliers as $s){ + echo "$s
${d} "; + foreach($suppliers as $s){ + $var="${s}-${d}"; + $val=$os->getVariable($var); + echo "$val
"; + +echo "\n"; + + +//capacity matrix +echo "

Capacity Matrix"; +echo ""; +} +echo ""; +echo ""; +foreach($supplierCap as $sc){ + echo ""; +} +echo ""; +echo "\n
\n"; + +foreach($suppliers as $s){ + echo "$s
$sc->capacity
"; + +echo "\n"; + + + +//Demand matrix +echo "

Demand Matrix"; +echo ""; +} +echo ""; +echo ""; +foreach($departmentDem as $dd){ + echo ""; +} +echo ""; +echo "\n
\n"; + +foreach($departments as $d){ + echo "$d
$dd->demand
"; + +echo "\n"; + +//Profit matrix +echo "

Profit Matrix"; +echo ""; +} +echo ""; +echo ""; +foreach($departmentDem as $dd){ + echo ""; +} +echo ""; +echo "\n
\n"; + +foreach($departments as $d){ + echo "$d
$$dd->profit
"; + +echo "\n"; + + +//Distance matrix +echo "

Distance Matrix"; +echo ""; +} +foreach($departments as $d){ + echo ""; + } + echo "\n"; +} +echo ""; +echo "\n
\n"; + +foreach($suppliers as $s){ + echo "$s
${d} "; + foreach($suppliers as $s){ + $var="${s}-${d}"; + $val=$distanceMatrix[$var]->distance; + echo "$val
"; +echo "\n"; +echo "\n\n"; +?> + + + \ No newline at end of file diff --git a/Web/E1bOutput.php b/Web/E1bOutput.php new file mode 100644 index 0000000..461a375 --- /dev/null +++ b/Web/E1bOutput.php @@ -0,0 +1,124 @@ + + + + + + +Exam 1 + + +

EXAM INPUT AND OUTPUT

+

+

+The maximum profit = $$os->solution"; + +//shipping matrix +echo "

Shipping Matrix"; +echo ""; +} +foreach($departments as $d){ + echo ""; + } + echo "\n"; +} +echo ""; +echo "\n
\n"; + +foreach($suppliers as $s){ + echo "$s
${d} "; + foreach($suppliers as $s){ + $var="${s}-${d}"; + $val=$os->getVariable($var); + echo "$val
"; + +echo "\n"; + + +//capacity matrix +echo "

Capacity Matrix"; +echo ""; +} +echo ""; +echo ""; +foreach($supplierCap as $sc){ + echo ""; +} +echo ""; +echo "\n
\n"; + +foreach($suppliers as $s){ + echo "$s
$sc->capacity
"; + +echo "\n"; + + + +//Demand matrix +echo "

Demand Matrix"; +echo ""; +} +echo ""; +echo ""; +foreach($departmentDem as $dd){ + echo ""; +} +echo ""; +echo "\n
\n"; + +foreach($departments as $d){ + echo "$d
$dd->demand
"; + +echo "\n"; + +//Profit matrix +echo "

Profit Matrix"; +echo ""; +} +echo ""; +echo ""; +foreach($departmentDem as $dd){ + echo ""; +} +echo ""; +echo "\n
\n"; + +foreach($departments as $d){ + echo "$d
$$dd->profit
"; + +echo "\n"; + + +//Distance matrix +echo "

Distance Matrix"; +echo ""; +} +foreach($departments as $d){ + echo ""; + } + echo "\n"; +} +echo ""; +echo "\n
\n"; + +foreach($suppliers as $s){ + echo "$s
${d} "; + foreach($suppliers as $s){ + $var="${s}-${d}"; + $val=$distanceMatrix[$var]->distance; + echo "$val
"; +echo "\n"; +echo "\n\n"; +?> + + + \ No newline at end of file diff --git a/Web/E1bRandom.php b/Web/E1bRandom.php new file mode 100644 index 0000000..4c11c47 --- /dev/null +++ b/Web/E1bRandom.php @@ -0,0 +1,135 @@ +demand=$dem; + $this->profit=$p; + } +} +for ($i=0; $i<$numDepartments;$i++){ + $cd=$departments[$i]; //cd = current department + $departmentDem["$departments[$i]"]=new Department(rand(0,1000),rand(10,50)); +} +class Supplier{ + public $supplier; + public $capacity; + + function __construct($s,$c){ + $this->supplier=$s; + $this->capacity=$c; + } +} +for ($x=0; $x<$numSuppliers;$x++){ + $cs=$suppliers[$x]; //cs = current supplier + $supplierCap["$suppliers[$x]"] = new Supplier($cs,rand(400,2000)); +} +//print_r($departmentDem); +//print_r($supplierCap); + +class Distance{ + + public $distance; + + function __construct($dist){ + $this->distance=$dist; + } +} + +for ($x=0; $x<$numSuppliers;$x++){ + for ($i=0; $i<$numDepartments;$i++){ + $cs=$suppliers[$x]; //cs = current supplier + $cd=$departments[$i]; //cd = current department + $distanceMatrix["$suppliers[$x]-$departments[$i]"]=new Distance(rand(1,50)); + } +} + +//print_r($distanceMatrix); + +$os=new \WebIS\OS; +//assertTrue($os->solve()); + + +//echo $distanceMatrix["S1-D1"]->distance; + +//setting up the objective function +foreach($suppliers as $s){ + foreach($departments as $d){ + $var="${s}-${d}"; + $os->addVariable($var); + $os->addObjCoef($var,$departmentDem[$d]->profit - $distanceMatrix["$var"]->distance); + //print $departmentDem[$d]->profit - $distanceMatrix["$var"]->distance; + //print "\n"; + //print "$var\n"; + + } +} + +//adding the constraints + + +$x=0; +foreach($supplierCap as $s ){ + $x+=1; + $ub = $s->capacity; + //print $ub; + //print $s; + $os->addConstraint(NULL,$ub); + foreach($departments as $k){ + $currentKey="S$x-${k}"; + $os->addConstraintCoef($currentKey,1); + } +} + +$x=0; +foreach($departmentDem as $d ){ + $x+=1; + $lb = $d->demand; + $os->addConstraint($lb,NULL); + foreach($suppliers as $k){ + $currentKey="${k}-D$x"; + $os->addConstraintCoef($currentKey,1); + } +} + +$os->solve(); + +//if you want to see this work please uncomment print_r($os); below + +//print_r($os); +?> diff --git a/Web/E1bRefactorRandom.php b/Web/E1bRefactorRandom.php new file mode 100644 index 0000000..eb845e0 --- /dev/null +++ b/Web/E1bRefactorRandom.php @@ -0,0 +1,135 @@ +demand=$dem; + $this->profit=$p; + } + } + + for ($i=0; $i<$numDepartments;$i++){ + $cd=$departments[$i]; //cd = current department + $departmentDem["$departments[$i]"]=new Department(rand(0,500),rand(10,50)); + } + + class Supplier{ + public $supplier; + public $capacity; + + function __construct($s,$c){ + $this->supplier=$s; + $this->capacity=$c; + } + } + + for ($x=0; $x<$numSuppliers;$x++){ + $cs=$suppliers[$x]; //cs = current supplier + $supplierCap["$suppliers[$x]"] = new Supplier($cs,rand(100,800)); + } + print_r($departmentDem); + print_r($supplierCap); + + class Distance{ + + public $distance; + function __construct($dist){ + $this->distance=$dist; + } + } + + for ($x=0; $x<$numSuppliers;$x++){ + for ($i=0; $i<$numDepartments;$i++){ + $cs=$suppliers[$x]; //cs = current supplier + $cd=$departments[$i]; //cd = current department + $distanceMatrix["$suppliers[$x]-$departments[$i]"]=new Distance(rand(1,8)); + } + } + + print_r($distanceMatrix); + + $os=new \WebIS\OS; + //assertTrue($os->solve()); + + + //echo $distanceMatrix["S1-D1"]->distance; + + //setting up the objective function + foreach($suppliers as $s){ + foreach($departments as $d){ + $var="${s}-${d}"; + $os->addVariable($var); + $os->addObjCoef($var,$departmentDem[$d]->profit - $distanceMatrix["$var"]->distance); + //print $departmentDem[$d]->profit - $distanceMatrix["$var"]->distance; + //print "\n"; + //print "$var\n"; + + } + } + + //adding the constraints + + $x=0; + foreach($supplierCap as $s ){ + $x+=1; + $ub = $s->capacity; + //print $ub; + //print $s; + $os->addConstraint(NULL,$ub); + foreach($departments as $k){ + $currentKey="S$x-${k}"; + $os->addConstraintCoef($currentKey,1); + } + } + + $x=0; + foreach($departmentDem as $d ){ + $x+=1; + $lb = $d->demand; + $os->addConstraint($lb,NULL); + foreach($suppliers as $k){ + $currentKey="${k}-D$x"; + $os->addConstraintCoef($currentKey,1); + } + } + + $os->solve(); + print_r($os); + return $os->solution; +} + +?> \ No newline at end of file diff --git a/Web/E1bRefactorRandomRun.php b/Web/E1bRefactorRandomRun.php new file mode 100644 index 0000000..184e96c --- /dev/null +++ b/Web/E1bRefactorRandomRun.php @@ -0,0 +1,12 @@ +demand=$dem; + $this->profit=$p; + } + } + + //this will add the demand and profit to each department based on the array that passes through + for($i=0;$i<$numDepartments;$i++){ + $departmentDem["$departments[$i]"]=new Department($demand[$i],$profit[$i]); + } + + class Supplier{ + public $capacity; + + function __construct($c){ + $this->capacity=$c; + } + } + + //this will set the capacities for each supplier based on the array that is passed + for($i=0;$i<$numSuppliers;$i++){ + $supplierCap["$suppliers[$i]"] = new Supplier($capacity[$i]); + } + + + print_r($departmentDem); + print_r($supplierCap); + + class Distance{ + + public $distance; + function __construct($dist){ + $this->distance=$dist; + } + } + + //obtains the distance between each station from the 2 dimensional array that is passed through function + for($i=0;$i<$numSuppliers;$i++){ + for($x=0;$x<$numDepartments;$x++){ + $distanceMatrix["$suppliers[$i]-$departments[$x]"]=new Distance($distance[$i][$x]); + } + } + + + print_r($distanceMatrix); + + $os=new \WebIS\OS; + //assertTrue($os->solve()); + + + //echo $distanceMatrix["S1-D1"]->distance; + + //setting up the objective function + foreach($suppliers as $s){ + foreach($departments as $d){ + $var="${s}-${d}"; + $os->addVariable($var); + $os->addObjCoef($var,$departmentDem[$d]->profit - $distanceMatrix["$var"]->distance); + print $departmentDem[$d]->profit - $distanceMatrix["$var"]->distance; + print "\n"; + //print "$var\n"; + +} +} + +//adding the constraints + +$x=0; +foreach($supplierCap as $s ){ + $x+=1; + $ub = $s->capacity; + //print $ub; + //print $s; + $os->addConstraint(NULL,$ub); + foreach($departments as $key){ + $currentKey="S$x-${key}"; + $os->addConstraintCoef($currentKey,1); + //print $currentKey; +} +} + +$x=0; +foreach($departmentDem as $d ){ + $x+=1; + $lb = $d->demand; + $os->addConstraint($lb,NULL); + foreach($suppliers as $k){ + $currKey="${k}-D$x"; + $os->addConstraintCoef($currKey,1); + //print $currentKey; +} +} + +$os->solve(); +print_r($os); + +return $os->solution; +} + +?> \ No newline at end of file diff --git a/Web/E1bRefactorStaticRun.php b/Web/E1bRefactorStaticRun.php new file mode 100644 index 0000000..a02bb0d --- /dev/null +++ b/Web/E1bRefactorStaticRun.php @@ -0,0 +1,38 @@ +demand=$dem; + $this->profit=$p; + } +} + + $departmentDem["$departments[0]"]=new Department(600,20); + $departmentDem["$departments[1]"]=new Department(200,30); + $departmentDem["$departments[2]"]=new Department(300,40); + + +class Supplier{ + public $capacity; + + function __construct($c){ + $this->capacity=$c; + } +} + + + $supplierCap["$suppliers[0]"] = new Supplier(600); + $supplierCap["$suppliers[1]"] = new Supplier(300); + $supplierCap["$suppliers[2]"] = new Supplier(200); + +print_r($departmentDem); +print_r($supplierCap); + +class Distance{ + + public $distance; + function __construct($dist){ + $this->distance=$dist; + } +} + + + $distanceMatrix["$suppliers[0]-$departments[0]"]=new Distance(2); + $distanceMatrix["$suppliers[0]-$departments[1]"]=new Distance(3); + $distanceMatrix["$suppliers[0]-$departments[2]"]=new Distance(3); + $distanceMatrix["$suppliers[1]-$departments[0]"]=new Distance(5); + $distanceMatrix["$suppliers[1]-$departments[1]"]=new Distance(2); + $distanceMatrix["$suppliers[1]-$departments[2]"]=new Distance(4); + $distanceMatrix["$suppliers[2]-$departments[0]"]=new Distance(3); + $distanceMatrix["$suppliers[2]-$departments[1]"]=new Distance(2); + $distanceMatrix["$suppliers[2]-$departments[2]"]=new Distance(8); + + +print_r($distanceMatrix); + +$os=new \WebIS\OS; +//assertTrue($os->solve()); + + +//echo $distanceMatrix["S1-D1"]->distance; + +//setting up the objective function +foreach($suppliers as $s){ + foreach($departments as $d){ + $var="${s}-${d}"; + $os->addVariable($var); + $os->addObjCoef($var,$departmentDem[$d]->profit - $distanceMatrix["$var"]->distance); + print $departmentDem[$d]->profit - $distanceMatrix["$var"]->distance; + print "\n"; + //print "$var\n"; + + } +} + +//adding the constraints + + +$x=0; +foreach($supplierCap as $s ){ + $x+=1; + $ub = $s->capacity; + //print $ub; + //print $s; + $os->addConstraint(NULL,$ub); + foreach($departments as $key){ + $currentKey="S$x-${key}"; + $os->addConstraintCoef($currentKey,1); + //print $currentKey; + } +} + +$x=0; +foreach($departmentDem as $d ){ + $x+=1; + $lb = $d->demand; + $os->addConstraint($lb,NULL); + foreach($suppliers as $k){ + $currKey="${k}-D$x"; + $os->addConstraintCoef($currKey,1); + //print $currentKey; + } +} + +$os->solve(); + +print_r($os); +?> + diff --git a/Web/modelbasic.php b/Web/modelbasic.php new file mode 100644 index 0000000..78b2e60 --- /dev/null +++ b/Web/modelbasic.php @@ -0,0 +1,236 @@ +modelbasic.php\n"; + +// Problem: Maximize productivity in a work-cell line. +// Workers are assigned a productivity score for each work-cell. +// Products are given a demand in normalized hours on a work-cell. +// Production is equal to (hours allocated) * (productivity on machine) + +// A: Setup. + +// A1: Use TDD functions from osbasic and store in tdd.php +// Use TDD from osbasic and place in tdd.php +require_once 'Work-Cell-Scheduler/WCS/os.php'; +require_once 'tdd.php'; +assertEquals(TRUE,TRUE); +assertTrue(TRUE); +assertFalse(FALSE); + +// B: Setup problem and data structures. + +$workers=5; +$cells=4; +$products=6; + +// B1: Create arrays of workers, cells and products (worker-1, cell-3, product-4) +// called worker,cell, and product + +$worker=array(); +for($i=0;$i<$workers;$i++){ + $worker[]="worker-${i}"; +} +assertEquals($workers,sizeof($worker)); +//print_r($worker); + +$cell=array(); +for($i=0;$i<$cells;$i++){ + $cell[]="cell-${i}"; +} +assertEquals($cells,sizeof($cell)); + +$product=array(); +for($i=0;$i<$products;$i++){ + $product[]="product-${i}"; +} +assertEquals($products,sizeof($product)); + +// B2: Pick at random a worker and test using TDD. +// make sure the first and last get picked. + +$w=0; +while($worker[$w] != 'worker-1'){ + $w=array_rand($worker); + //print_r($w); +} + +// B3: Create demand using a structure/class that holds (product,cell,hours). +// Hours is between 1 and 3 hours: rand(1,3) + +class Demand { + public $product=NULL; + public $cell=NULL; + public $hours=NULL; + function __construct($product,$cell,$hours){ + $this->product=$product; + $this->cell=$cell; + $this->hours=$hours; + } +} + +$demand=array(); +foreach($product as $p){ + $demand[]=new Demand($p,$cell[array_rand($cell)],rand(1,3)); +} + +assertEquals($products,sizeof($demand)); +//print_r($demand); + +// B4: Create training matrix class to hold worker/cell productivity +// If a worker/cell does not exist return a default value (which could be FALSE). +// access with set(worker,cell,productivity) and get(...) +// Use an array with the key as a string, join elements with the underscore symbol ('_') +// Note in the "" syntax use the form ${worker} instead of $worker. + +class Training { + private $default=FALSE; + private $matrix=array(); + function set($worker,$cell,$productivity){ + $this->matrix["${worker}_${cell}"]=$productivity; + } + function get($worker,$cell){ + if(array_key_exists("${worker}_${cell}",$this->matrix)){ + return $this->matrix["${worker}_${cell}"]; + } + return $this->default; + } +} + +$training=new Training; + +// B5: Use TDD to check get/set + +assertEquals(FALSE,$training->get('worker-1','cell-1')); +$training->set('worker-1','cell-1',0.99); +assertEquals(0.99,$training->get('worker-1','cell-1')); + +// B6: Populate training with a number of random trainings + +for($i=0;$i<20;$i++){ + $training->set($worker[array_rand($worker)],$cell[array_rand($cell)],rand(70,100)/100.0); +} +//print_r($training); + + +// C: Optimization + +// C0: Solve empty problem. +$os=new \WebIS\OS; +assertTrue($os->solve()); + +// C1: Setup objective function, minimize worker hours on each cell +foreach($worker as $w){ + foreach($cell as $c){ + $var="${w}_${c}"; + $os->addVariable($var); + $os->addObjCoef($var,1); + } +} + +assertTrue($os->solve()); +//print_r($os); + +// C2: build production requirement, +// How much work is required on each cell. +// Calculate total production hours (used to check later). + +$celltotal=array(); +foreach($cell as $c){ + $celltotal[$c]=0.0; +} +foreach($demand as $d){ + $celltotal[$d->cell]+=$d->hours; +} +//print_r($celltotal); + +$required=0.0; +foreach($celltotal as $c=>$v){ + $required+=$v; +} +assertTrue($required>0.0); +//print_r("total: $required\n"); + + +// C3: Generate constraints off this (note OS changed to $ub,$lb and made required) and solve. +// Multiply the hours worked by productivity to get the amount of hours that are needed to work +// to fulfill the requirements. +// If there is no training do not include in problem. + +foreach($celltotal as $c=>$lb){ + $os->addConstraint($lb,NULL); + foreach($worker as $w){ + $var="${w}_${c}"; + $val=$training->get($w,$c); + if($val!==FALSE){ + $os->addConstraintCoef("${w}_${c}",$val); + } + } +} + +assertTrue($os->solve()); +$solution=$os->getSolution(); +//print_r("solution: $solution\n"); + +// C4: check that the total hours allocated is at least the total required. + +$worked=0.0; +foreach($worker as $w){ + foreach($cell as $c){ + $var="${w}_${c}"; + $val=$os->getVariable($var); + $worked+=$val; + } +} + +assertTrue($worked>=$required); + +// C5: Cap worker hours to 8 a day. + +foreach($worker as $w){ + $os->addConstraint(NULL,8); + foreach($cell as $c){ + $var="${w}_${c}"; + $val=$training->get($w,$c); + if($val!==FALSE){ + $os->addConstraintCoef("${w}_${c}",1); + } + + } +} + +assertTrue($os->solve()); +$solution=$os->getSolution(); +//print_r("solution: $solution\n"); + +// D: Verify solution. + +// D1: Dump solution to a html table (readable in the console as well), and verify solution by hand. +// include productivity and product. +// Worker as rows, cells as columns. + +echo ""; +} +foreach($worker as $w){ + echo ""; + } + echo "\n"; +} +echo ""; +foreach($celltotal as $ct){ + echo ""; +} +echo ""; + +echo "\n
\n"; +foreach($cell as $c){ + echo "$c
${w}: "; + foreach($cell as $c){ + $var="${w}_${c}"; + $val=$os->getVariable($var); + $t=$training->get($w,$c); + echo "$val $t ".$val*$t."
Total$ct
"; + + +// Done +echo "\n\n"; +?> diff --git a/Web/os.php b/Web/os.php new file mode 100644 index 0000000..7951d14 --- /dev/null +++ b/Web/os.php @@ -0,0 +1,11 @@ +"; + } +} + + +?> diff --git a/Web/osTest.php b/Web/osTest.php new file mode 100644 index 0000000..9d6413e --- /dev/null +++ b/Web/osTest.php @@ -0,0 +1,27 @@ + + + $os=new OS(); + $this->assertEquals("",$os->osil()); + } + +} + + +if (!defined('PHPUnit_MAIN_METHOD')) { + WebOSTestCase::main(); +} +?> diff --git a/Web/osbasic.php b/Web/osbasic.php new file mode 100644 index 0000000..a93e605 --- /dev/null +++ b/Web/osbasic.php @@ -0,0 +1,281 @@ + +// SimpleXMLElement is a class, look at the asXML method to return the string. +// Use the XML heredoc for the expected result + +function osil() { + $xml=new SimpleXMLElement(''); + return $xml->asXML(); +} + +$xml=<< + + +XML; + +assertEquals($xml,osil()); + +// Problem 6: Write assertContainsString($needle,$haystack) + +function assertContainsString($needle,$haystack){ + if(strpos($haystack,$needle)===FALSE){ + $message="assertContainsString: |$needle|$haystack|"; + throw new Exception($message); + } +} + +assertContainsString('Needle','HayStack Needle Hay Hay'); +$failed=FALSE; +try { + assertContainsString('Needle','All hay'); // Fails +} catch (Exception $e) { + $failed=TRUE; +} +assert($failed); + +// Problem 7: The haystack can be an array of strings + +function assertContains($needle,$haystack){ + if(is_string($haystack)){ + return assertContainsString($needle,$haystack); + } + foreach($haystack as $hay) + if(strpos($hay,$needle)!==FALSE){ + return; + } + $message="assertContains: |$needle|$haystack|"; + throw new Exception($message); +} + +assertContains('Needle',array('HayStack Needle Hay Hay','Hay')); + + +// Problem 7: Run "OSSolverService -h" make sure it returns 0 and contains the string "OS Version: 2." +// use the exec function +// The program in ..\\..\\..\\bin\\OSSolverService.exe + +// Make sure to test failure first. + +exec("..\\..\\..\\bin\\OSSolverService.exe -h",$output,$result); +//print_r($output); +assertEquals(0,$result); +assertContains("OS Version: 2.",$output); + +// Problem 8: Save the xml to test.xml and read it back to test it. +// reimplement osil() as a write() function. +// read + +function write($file) { + $xml=new SimpleXMLElement(''); + return $xml->asXML($file); +} + +write("test.xml"); +$xml=file_get_contents("test.xml"); +// print_r($xml); +assertContains('',$xml); + +// Problem 9: Create a function solve() "OSSolverService -osil test.xml" that throws an exception on failure +// Assume test.xml is there. +// Our problem should return a result of nonzero since it is not well formed. +// Actually it crashes. + +function solve(){ + exec("..\\..\\..\\bin\\OSSolverService.exe -osil test.xml -osrl solution.xml",$output,$result); + //print_r($output); + if($result!==0){ + $message="solve: error $result\n".implode("\n",$output); + throw new Exception($message); + } +} + +$failed=FALSE; +try { + solve(); +} catch (Exception $e){ + //print $e; + $failed=TRUE; +}; +assert($failed); + +// Problem 10: +// Generate a minimal osil document and solve() it +// + +$xml=new SimpleXMLElement(''); +$xml->addChild('instanceHeader'); +$xml->addChild('instanceData')->addChild('objectives')->addChild('obj')->addAttribute('numberOfObjCoef',0); + +//print $xml->asXML(); +$xml->asXML('test.xml'); +solve(); + +// Problem 11: +// Detect an error and report it. + +// Problem 12: Verify the minimal solution() status is "optimal" and 0, return FALSE if not optimal. +// write the output in solve() to soution.xml with the "-osrl solution.xml" switch +// parse it with simplexml_load_file +// print_r is your friend. +// You must also often cast and simpleXMLElement to a string "(string)" + +function solution(){ + solve(); + $osrl=simplexml_load_file('solution.xml'); + //print_r($osil->optimization); + $result=(string)$osrl->optimization->solution->status->attributes()->type; + if($result!=='optimal'){ + return FALSE; + } + return (int)$osrl->optimization->solution->objectives->values->obj; +} + +//assertEquals(0,solution()); + +// A bit troublesome since it generates warnings +// Not all that useful as well. + +// Problem 13: Refactor solve and solution and fix warnings. Call it solveProblem() +// This generates a warning, the XML emitted is non-conforming, fix. +// The xmlns needs a proper "uri" so we add http:// to the xmlns string. +// New function takes an SimpleXMLElement and returns the solution. +// Write the file to a temporary file using tempnam() in ..\\..\\..\\tmp +// get a file into a string with get_file_contents +// use preg_replace to alter the file. +// remove the files with unlink() when done. + +function solveProblem(SimpleXMLElement $osil){ + $osilfile=tempnam('..\\..\\..\\tmp','OS-'); + $osrlfile=tempnam('..\\..\\..\\tmp','OS-'); + $osil->asXML($osilfile); + exec("..\\..\\..\\bin\\OSSolverService.exe -osil $osilfile -osrl $osrlfile",$output,$result); + //print_r($output); + if($result!==0){ + $message="solve: error $result\n".implode("\n",$output); + throw new Exception($message); + } + $xml=file_get_contents($osrlfile); + if($xml==FALSE){ + return FALSE; + } + if(strpos($xml,'')!==FALSE){ + throw new Exception("solve: error in OSrL:".$xml); + } + //unlink($osilfile); + //unlink($osrlfile); + $xml=preg_replace('/"os.optimizationservices.org"/','"http://os.optimizationservices.org"',$xml); + //print_r($xml); + $osrl=new SimpleXMLElement($xml); + //print_r($osrl->optimization); + $result=(string)$osrl->optimization->solution->status->attributes()->type; + if($result!=='optimal'){ + return FALSE; + } + return (int)$osrl->optimization->solution->objectives->values->obj; +} + +assertEquals(0,solveProblem($xml)); + +// Problem 14: Create a template SimpleXMLElement in order to easily construct problems. +// Creating a function to generate a template called emptyProblem() +// be sure to include the instanceHeader->name element (populate it with the date) +// You can "chain" elements in $xml->addChild('foo')->addChild('bar') +// You can find the template in Test/osTest.php +// Don't include any namespace (xmlns) material, OSSolverService does not care. +// Debug with print_r($xml) +// Errors do not produce well formed XML. Detect this in your solveProblem function. +// For TDD simply test non zero: assert(emptyProblem()) will be tested in the next problem. + +function emptyProblem(){ + $xml=new SimpleXMLElement(''); + $xml->addChild('instanceHeader')->addChild('name'); + $data=$xml->addChild('instanceData'); + $data->addChild('objectives')->addChild('obj')->addAttribute('numberOfObjCoef',0); + $data->addChild('constraints')->addAttribute('numberOfConstraints',0); + $constraints=$data->addChild('linearConstraintCoefficients'); + $constraints->addAttribute('numberOfValues',0); + $constraints->addChild('start')->addChild('el'); + $constraints->addChild('colIdx'); + $constraints->addChild('value'); + //print_r($xml); + return $xml; +} + +assert(emptyProblem()); + +// Problem 15: Solve the homework problem by passing a SimpleXMLElement to solveOsil(). +// Start with emptyProblem() +// test against your minimal problem + +// Problem 16: Generalize and implement as a class. + +echo "done.\n" + +?> diff --git a/Web/problembasic.php b/Web/problembasic.php new file mode 100644 index 0000000..fb0b46f --- /dev/null +++ b/Web/problembasic.php @@ -0,0 +1,274 @@ +problembasic.php\n"; +require_once 'Work-Cell-Scheduler/WCS/os.php'; +require_once 'tdd.php'; + +// E: Refactor modelbasic.php to problembasic.php. +// Make the problem a class so that it can be replaced by a Business Object backed by a database at some point. + +class SimpleProblem { + + // E1 + private $workers=5; + private $cells=4; + private $products=6; + + // E4 + /** + * Solver + * @var \WebIS\OS + */ + private $os=NULL; + + // E1 + function loadProblem($workers,$cells,$products){ + $this->workers=$workers; + $this->cells=$cells; + $this->products=$products; + + $worker=array(); + for($i=0;$i<$workers;$i++){ + $worker[]="worker-${i}"; + } + $this->worker=$worker; + + $cell=array(); + for($i=0;$i<$cells;$i++){ + $cell[]="cell-${i}"; + } + $this->cell=$cell; + + $product=array(); + for($i=0;$i<$products;$i++){ + $product[]="product-${i}"; + } + $this->product=$product; + } + + // E2 + function loadDemand(){ + $demand=array(); + foreach($this->product as $p){ + $c=$this->cell[array_rand($this->cell)]; + $d=rand(1,3); + $var="${p}_${c}"; + $demand[$var]=new Demand($p,$c,$d); + } + $this->demand=$demand; + } + + // E3 + function loadTraining() { + $training=new Training; + for($i=0;$i<20;$i++){ + $training->set($this->worker[array_rand($this->worker)],$this->cell[array_rand($this->cell)],rand(70,100)/100.0); + } + $this->training=$training; + } + + // E4 + function calculate() { + $celltotal=array(); + foreach($this->cell as $c){ + $celltotal[$c]=0.0; + } + foreach($this->demand as $var=>$d){ + $celltotal[$d->cell]+=$d->hours; + } + $this->celltotal=$celltotal; + + $required=0.0; + foreach($celltotal as $c=>$v){ + $required+=$v; + } + $this->required=$required; + } + + // E5 + function displayWorkers() { + $output=array(); + $solution=''; + if($this->os){ + $solution=$this->os->getSolution(); + } + $output[]=""; + } + $output[]=""; + } + $output[]=""; + foreach($this->celltotal as $ct){ + $output[]=""; + } + $output[]=""; + + $output[]="\n
$solution\n"; + foreach($this->cell as $c){ + $output[]="$cTotal\n"; + $total=0.0; + foreach($this->worker as $w){ + $output[]="
${w}"; + $hours=0.0; + foreach($this->cell as $c){ + $var="${w}_${c}"; + $t=$this->training->get($w,$c); + if($this->os){ + $val=$this->os->getVariable($var); + $hours+=$val; + $total+=$val*$t; + }else{ + $val=''; + } + $output[]="$val$t".$val*$t; + } + $output[]="$hours
Total$ct$total
\n"; + return implode(" ",$output); + } + + // E6 + function displayProblem() { + $output=array(); + $output[]=""; + } + $output[]=""; + } + $output[]=""; + $total=0.0; + foreach($this->celltotal as $ct){ + $output[]=""; + $total+=$ct; + } + $output[]=""; + + $output[]="\n
\n"; + foreach($this->cell as $c){ + $output[]="$cTotal\n"; + foreach($this->product as $p){ + $output[]="
${p}"; + $total=0.0; + foreach($this->cell as $c){ + $hours=0.0; + $var="${p}_${c}"; + if(array_key_exists($var,$this->demand)){ + $d=$this->demand[$var]; + $hours=$d->hours; + } + $output[]="$hours"; + $total+=$hours; + } + $output[]="$hours
Total$ct$total
\n"; + return implode(" ",$output); + } + + // E7 Solve + function solve(){ + $os=new \WebIS\OS; + + $worker=$this->worker; + $cell=$this->cell; + + // Variables and objective function + foreach($worker as $w){ + foreach($cell as $c){ + $var="${w}_${c}"; + $os->addVariable($var); + $os->addObjCoef($var,1); + } + } + + // Production constraints (use effective hours for productivity) + $celltotal=$this->celltotal; + $training=$this->training; + foreach($celltotal as $c=>$lb){ + $os->addConstraint($lb,NULL); + foreach($worker as $w){ + $var="${w}_${c}"; + $val=$training->get($w,$c); + if($val!==FALSE){ + $os->addConstraintCoef("${w}_${c}",$val); + } + } + } + // Maximum 8 hours per week. + foreach($worker as $w){ + $os->addConstraint(NULL,8); + foreach($cell as $c){ + $var="${w}_${c}"; + $val=$training->get($w,$c); + if($val!==FALSE){ + $os->addConstraintCoef("${w}_${c}",1); + } + } + } + + $this->os=$os; + return $os->solve(); + } + +} + + +class Demand { + // E2 + public $product=NULL; + public $cell=NULL; + public $hours=NULL; + + // E2 + function __construct($product,$cell,$hours){ + $this->product=$product; + $this->cell=$cell; + $this->hours=$hours; + } +} + +class Training { + // E3 + private $default=FALSE; + private $matrix=array(); + + // E3 + function set($worker,$cell,$productivity){ + $this->matrix["${worker}_${cell}"]=$productivity; + } + + // E3 + function get($worker,$cell){ + if(array_key_exists("${worker}_${cell}",$this->matrix)){ + return $this->matrix["${worker}_${cell}"]; + } + return $this->default; + } +} + + +// E1: Use an empty constructor and use a function call loadProblem() with workers,cells, and products +// This function generates the list of workers, cells, and products. +// Store in an associative array with product_cell as key. + +$p=new SimpleProblem; +$p->loadProblem(5,4,6); + +// E2: Refactor demand generation as loadDemand() +$p->loadDemand(); + +// E3: Refactor training generation as loadTraining() +$p->loadTraining(); + +// E4: Refactor Calculate values (cell totals, overall total) with calculate(); +$p->calculate(); + +// E5: Refactor display solution (empty) to verify problem with displayWorkers(); include row and column sum. +//echo $p->displayWorkers(); + +// E6: Create a displayProblem function to show product/cell demand, include row and column sum. +//echo $p->displayProblem(); + +// E7: Refactor solve() and redisplay +// echo "
\n"; +$p->solve(); +echo $p->displayWorkers(); +echo $p->displayProblem(); + +echo "\n\n"; +?> \ No newline at end of file diff --git a/Web/problemdata.php b/Web/problemdata.php new file mode 100644 index 0000000..c387628 --- /dev/null +++ b/Web/problemdata.php @@ -0,0 +1,271 @@ +problembasic.php\n"; +require_once 'Work-Cell-Scheduler/WCS/os.php'; +require_once 'tdd.php'; + +// F: Refactor the "data" out of the class into a $data and $problem. + +class SimpleProblemData { + + // E1 + private $workers=5; + private $cells=4; + private $products=6; + + // E1 + function loadProblem($workers,$cells,$products){ + $this->workers=$workers; + $this->cells=$cells; + $this->products=$products; + + $worker=array(); + for($i=0;$i<$workers;$i++){ + $worker[]="worker-${i}"; + } + $this->worker=$worker; + + $cell=array(); + for($i=0;$i<$cells;$i++){ + $cell[]="cell-${i}"; + } + $this->cell=$cell; + + $product=array(); + for($i=0;$i<$products;$i++){ + $product[]="product-${i}"; + } + $this->product=$product; + } + + // E2 + function loadDemand(){ + $demand=array(); + foreach($this->product as $p){ + $c=$this->cell[array_rand($this->cell)]; + $d=rand(1,3); + $var="${p}_${c}"; + $demand[$var]=new Demand($p,$c,$d); + } + $this->demand=$demand; + } + + // E3 + function loadTraining() { + $training=new Training; + for($i=0;$i<20;$i++){ + $training->set($this->worker[array_rand($this->worker)],$this->cell[array_rand($this->cell)],rand(70,100)/100.0); + } + $this->training=$training; + } + + // E4 + function calculate() { + $celltotal=array(); + foreach($this->cell as $c){ + $celltotal[$c]=0.0; + } + foreach($this->demand as $var=>$d){ + $celltotal[$d->cell]+=$d->hours; + } + $this->celltotal=$celltotal; + + $required=0.0; + foreach($celltotal as $c=>$v){ + $required+=$v; + } + $this->required=$required; + } + +} + + +class ProblemModel { + + /** + * Solver + * @var \WebIS\OS + */ + private $os=NULL; + private $data=NULL; + + // F + function __construct($data){ + $this->data=$data; + } + + // E5 + function displayWorkers() { + $data=$this->data; + $output=array(); + $solution=''; + if($this->os){ + $solution=$this->os->getSolution(); + } + $output[]=""; + } + $output[]=""; + } + $output[]=""; + foreach($data->celltotal as $ct){ + $output[]=""; + } + $output[]=""; + + $output[]="\n
$solution\n"; + foreach($data->cell as $c){ + $output[]="$cTotal\n"; + $total=0.0; + foreach($data->worker as $w){ + $output[]="
${w}"; + $hours=0.0; + foreach($data->cell as $c){ + $var="${w}_${c}"; + $t=$data->training->get($w,$c); + if($this->os){ + $val=$this->os->getVariable($var); + $hours+=$val; + $total+=$val*$t; + }else{ + $val=''; + } + $output[]="$val$t".$val*$t; + } + $output[]="$hours
Total$ct$total
\n"; + return implode(" ",$output); + } + + // E6 + function displayProblem() { + $data=$this->data; + $output=array(); + $output[]=""; + } + $output[]=""; + } + $output[]=""; + $total=0.0; + foreach($data->celltotal as $ct){ + $output[]=""; + $total+=$ct; + } + $output[]=""; + + $output[]="\n
\n"; + foreach($data->cell as $c){ + $output[]="$cTotal\n"; + foreach($data->product as $p){ + $output[]="
${p}"; + $total=0.0; + foreach($data->cell as $c){ + $hours=0.0; + $var="${p}_${c}"; + if(array_key_exists($var,$data->demand)){ + $d=$data->demand[$var]; + $hours=$d->hours; + } + $output[]="$hours"; + $total+=$hours; + } + $output[]="$hours
Total$ct$total
\n"; + return implode(" ",$output); + } + + // E7 Solve + function solve(){ + $os=new \WebIS\OS; + + $worker=$this->data->worker; + $cell=$this->data->cell; + + // Variables and objective function + foreach($worker as $w){ + foreach($cell as $c){ + $var="${w}_${c}"; + $os->addVariable($var); + $os->addObjCoef($var,1); + } + } + + // Production constraints (use effective hours for productivity) + $celltotal=$this->data->celltotal; + $training=$this->data->training; + foreach($celltotal as $c=>$lb){ + $os->addConstraint($lb,NULL); + foreach($worker as $w){ + $var="${w}_${c}"; + $val=$training->get($w,$c); + if($val!==FALSE){ + $os->addConstraintCoef("${w}_${c}",$val); + } + } + } + // Maximum 8 hours per week. + foreach($worker as $w){ + $os->addConstraint(NULL,8); + foreach($cell as $c){ + $var="${w}_${c}"; + $val=$training->get($w,$c); + if($val!==FALSE){ + $os->addConstraintCoef("${w}_${c}",1); + } + } + } + + $this->os=$os; + return $os->solve(); + } + +} + + +class Demand { + // E2 + public $product=NULL; + public $cell=NULL; + public $hours=NULL; + + // E2 + function __construct($product,$cell,$hours){ + $this->product=$product; + $this->cell=$cell; + $this->hours=$hours; + } +} + +class Training { + // E3 + private $default=FALSE; + private $matrix=array(); + + // E3 + function set($worker,$cell,$productivity){ + $this->matrix["${worker}_${cell}"]=$productivity; + } + + // E3 + function get($worker,$cell){ + if(array_key_exists("${worker}_${cell}",$this->matrix)){ + return $this->matrix["${worker}_${cell}"]; + } + return $this->default; + } +} + + +$d=new SimpleProblemData; +$d->loadProblem(5,4,6); + +$d->loadDemand(); +$d->loadTraining(); +$d->calculate(); + +$m=new ProblemModel($d); +$m->solve(); +echo $m->displayWorkers(); +echo $m->displayProblem(); + +// G: Replace the generated $data with one supplied by a database $data. + +echo "\n\n"; +?> \ No newline at end of file diff --git a/Web/tdd.php b/Web/tdd.php new file mode 100644 index 0000000..3783c35 --- /dev/null +++ b/Web/tdd.php @@ -0,0 +1,46 @@ +