From 7b7c02bcf2dd14737385196f30344e27939861aa Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Sun, 28 Sep 2025 21:53:23 -0400 Subject: [PATCH 01/19] started on more extensive README.md --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 2b17da4..3b7642d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ # simplex A small library used to demonstrate the concepts of the Simplex algorithm in convex optimization. + +# Installation + +You can add this module to your package using: +```bash +go get github.com/MatProGo-dev/simplex +``` + +# Usage + +TBD \ No newline at end of file From 65738b4aea52633c89b0c693f15db71e52148635 Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Fri, 3 Oct 2025 00:26:26 -0400 Subject: [PATCH 02/19] Updated dependencies to less buggy SymbolicMath.go + MatProInterface.go --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 583e021..c08390e 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.0 toolchain go1.23.9 require ( - github.com/MatProGo-dev/MatProInterface.go v0.5.5 - github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1 + github.com/MatProGo-dev/MatProInterface.go v0.5.6 + github.com/MatProGo-dev/SymbolicMath.go v0.2.5 gonum.org/v1/gonum v0.16.0 ) diff --git a/go.sum b/go.sum index fca3c9b..168c097 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ -github.com/MatProGo-dev/MatProInterface.go v0.5.5 h1:mq4hxTXz9msY0hEKqrKLJB4Ne0jfv4itaZAx3LV/l7A= -github.com/MatProGo-dev/MatProInterface.go v0.5.5/go.mod h1:UtPWsYyLFvssLYPZkiyMpgb9R9aTL8J4y1GfrM4phvc= -github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1 h1:SIj6oFJgavWtArs8toeHCPfxOefGMplWSkNvlR9P2Ac= -github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU= +github.com/MatProGo-dev/MatProInterface.go v0.5.6 h1:rzoT536J0sWQEJttc3vSsJ/ESgEg95NU2SbtaaGmUs4= +github.com/MatProGo-dev/MatProInterface.go v0.5.6/go.mod h1:o/uWBdqnA6YXq0enVlFEwM6raLnV2xC0liXqRe8FrPA= +github.com/MatProGo-dev/SymbolicMath.go v0.2.5 h1:fGpwtywb2hUXvGKk1Te6PQEfHeVar5w05KTbc3wHj6A= +github.com/MatProGo-dev/SymbolicMath.go v0.2.5/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= From ec8ae5c361fa356edb50162f76941d7aa5a96d8f Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Fri, 3 Oct 2025 00:26:46 -0400 Subject: [PATCH 03/19] Attempting to fix bug in how we solve from tableau --- algorithms/tableau/state.go | 2 +- examples/gonum_bug1/try_bug.go | 92 ++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 examples/gonum_bug1/try_bug.go diff --git a/algorithms/tableau/state.go b/algorithms/tableau/state.go index 84103cd..99a205f 100644 --- a/algorithms/tableau/state.go +++ b/algorithms/tableau/state.go @@ -288,7 +288,7 @@ func (state *TableauAlgorithmState) CalculateOptimalSolution() (mat.VecDense, er // - The non-basic variables set to zero A, b := state.A(), state.B() numConstraints, _ := A.Dims() - numNonBasic := state.NumberOfVariables() - state.NumberOfConstraints() + numNonBasic := state.Tableau.NumberOfNonBasicVariables() //state.NumberOfVariables() - state.NumberOfConstraints() // Augment the A and b matrices with the non-basic variable constraints AAugmented := mat.NewDense(numConstraints+numNonBasic, numVars, nil) diff --git a/examples/gonum_bug1/try_bug.go b/examples/gonum_bug1/try_bug.go new file mode 100644 index 0000000..727c693 --- /dev/null +++ b/examples/gonum_bug1/try_bug.go @@ -0,0 +1,92 @@ +package main + +import ( + "github.com/MatProGo-dev/MatProInterface.go/problem" + getKMatrix "github.com/MatProGo-dev/SymbolicMath.go/get/KMatrix" + getKVector "github.com/MatProGo-dev/SymbolicMath.go/get/KVector" + "github.com/MatProGo-dev/simplex/simplexSolver" + "gonum.org/v1/gonum/mat" +) + +/* +Description: + + Builds a version of a linear programming problem mentioned in this issue in gonum: + + https://github.com/gonum/gonum/issues/1914 + + This problem is very large and was causing issues in Gonum's LP solver. + + We will use this problem to test our own simplex solver implementation. +*/ +func BuildOptimizationProblem() problem.OptimizationProblem { + // setup + varCount := 57 + out := problem.NewProblem("Gonum Bug LP Problem") + + // Create the variables + x := out.AddVariableVector(varCount) + + // Create the objective + c := getKVector.From( + []float64{10, 5, 7, 10, 10, 5, 20, 20, 20, 20, 7, 5, 10, 80, 80, 10, 5, 5, 80, 80, 10, 80, 10, 7, 10, 10, 80, 7, 10, 20, 10, 7, 10, 7, 10, 15, 10, 10, 80, 10, 5, 7, 5, 10, 20, 10, 5, 10, 80, 80, 5, 10, 7, 7, 10, 5, 7}, + ) + out.SetObjective( + c.Transpose().Multiply(x), + problem.SenseMinimize, + ) + + // Create the constraints + // - Linear Equality Constraints + b := getKVector.From( + []float64{38, 5, 2, 33, 28, 14, 2, 48, 8, 133, 117, 34, 48, 20, 16, 50, 30, 75, 10, 40, 6, 70, 10, 5, 167, 13, 2, 118, 12, 98, 67, 157, 55, 2, 4, 4, 25, 4}, + ) + + Abuf := []float64{ + 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.95} + A := mat.NewDense(38, varCount, Abuf) + + out.Constraints = append( + out.Constraints, + getKMatrix.From(A).Multiply(x).Eq(b), + ) + + // - Linear Inequality Constraints + h := getKVector.From( + []float64{3370, 1031, 2350, 2289, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + ) + Gbuf := []float64{1, 0, 0, 1, 1, 0, 2, 2, 0, 2, 0, 0, 1, 0, 8, 1, 0, 0, 8, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 8, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 8, 0, 8, 1, 0, 0, 1, 8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1} + G := mat.NewDense(6+varCount, varCount, Gbuf) + + out.Constraints = append( + out.Constraints, + getKMatrix.From(G).Multiply(x).LessEq(h), + ) + + return *out + +} + +func main() { + // This is just a placeholder to make the package "main" valid. + trickyProblem := BuildOptimizationProblem() + + // Use solver to solve the problem + solver := simplexSolver.New("Simplex Solver Example") + solver.IterationLimit = 100 + + // Solve the problem + solution, err := solver.Solve(trickyProblem) + if err != nil { + panic(err) + } + + // Print the solution + solutionMessage, _ := solution.Status.ToMessage() + println("Solution Status: ", solutionMessage) + println("Objective Value: ", solution.Objective) + println("Variable Values: ") + for varName, varValue := range solution.Values { + println(" ", varName, ": ", varValue) + } +} From 5b5c414844268a50c4deb7d4210f7a1e4de9039b Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Sat, 4 Oct 2025 14:07:48 -0400 Subject: [PATCH 04/19] Upgraded package dependencies + introduced simplex solution object --- algorithms/algorithm_interface.go | 3 +- algorithms/stanford/stanford.go | 30 ++++++++++--------- algorithms/tableau/state.go | 13 ++++---- algorithms/tableau/tableau_algo.go | 13 ++++---- .../tableau/termination/termination_types.go | 12 ++++---- examples/gonum_bug1/try_bug.go | 2 +- .../the_simplex_method_part_ii.go | 2 +- go.mod | 2 +- go.sum | 2 ++ simplexSolver/solver.go | 5 ++-- solution/simplex_solution.go | 9 ++++++ 11 files changed, 55 insertions(+), 38 deletions(-) create mode 100644 solution/simplex_solution.go diff --git a/algorithms/algorithm_interface.go b/algorithms/algorithm_interface.go index 46625bb..64a3e96 100644 --- a/algorithms/algorithm_interface.go +++ b/algorithms/algorithm_interface.go @@ -2,9 +2,10 @@ package algorithms import ( "github.com/MatProGo-dev/MatProInterface.go/problem" + simplex_solution "github.com/MatProGo-dev/simplex/solution" ) type AlgorithmInterface interface { // Solves the provided optimization problem. - Solve(prob problem.OptimizationProblem) (problem.Solution, error) + Solve(prob problem.OptimizationProblem) (simplex_solution.SimplexSolution, error) } diff --git a/algorithms/stanford/stanford.go b/algorithms/stanford/stanford.go index badaabe..089192f 100644 --- a/algorithms/stanford/stanford.go +++ b/algorithms/stanford/stanford.go @@ -4,7 +4,9 @@ import ( "fmt" "github.com/MatProGo-dev/MatProInterface.go/problem" + solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" "github.com/MatProGo-dev/SymbolicMath.go/symbolic" + simplex_solution "github.com/MatProGo-dev/simplex/solution" "github.com/MatProGo-dev/simplex/utils" "gonum.org/v1/gonum/mat" ) @@ -178,11 +180,11 @@ Description: - The values of the basic variables - The values of the non-basic variables */ -func (algo *StanfordAlgorithm) ComputeSolutionFromState(state StanfordAlgorithmState) (problem.Solution, error) { +func (algo *StanfordAlgorithm) ComputeSolutionFromState(state StanfordAlgorithmState) (simplex_solution.SimplexSolution, error) { // Setup fmt.Printf("Computing solution from state...\n") - solution := problem.Solution{ - Status: problem.OptimizationStatus_OPTIMAL, + solution := simplex_solution.SimplexSolution{ + Status: solution_status.OPTIMAL, } // Compute the feasible solution of the basic variables @@ -200,18 +202,18 @@ func (algo *StanfordAlgorithm) ComputeSolutionFromState(state StanfordAlgorithmS // Set the values of the basic variables for ii, bv := range state.BasicVariables { - solution.Values[bv.ID] = xBasic.AtVec(ii) + solution.VariableValues[bv.ID] = xBasic.AtVec(ii) } // Set the values of the non-basic variables for jj, nv := range state.GetNonBasicVariables() { - solution.Values[nv.ID] = state.NonBasicValues.AtVec(jj) + solution.VariableValues[nv.ID] = state.NonBasicValues.AtVec(jj) } return solution, nil } -func (algo *StanfordAlgorithm) Solve(initialState StanfordAlgorithmState) (problem.Solution, error) { +func (algo *StanfordAlgorithm) Solve(initialState StanfordAlgorithmState) (simplex_solution.SimplexSolution, error) { // Setup var stateII StanfordAlgorithmState = initialState @@ -221,7 +223,7 @@ func (algo *StanfordAlgorithm) Solve(initialState StanfordAlgorithmState) (probl // Test for Termination r, err := stateII.GetReducedCostVector() if err != nil { - return problem.Solution{}, fmt.Errorf( + return simplex_solution.SimplexSolution{}, fmt.Errorf( "StanfordAlgorithm: Failed to get reduced cost vector (%v) at iteration #%v", err, iter, @@ -248,7 +250,7 @@ func (algo *StanfordAlgorithm) Solve(initialState StanfordAlgorithmState) (probl var ABasicInv mat.Dense ABasic, err := stateII.ABasic() if err != nil { - return problem.Solution{}, fmt.Errorf("StanfordAlgorithm: Failed to get ABasic matrix (%v)", err) + return simplex_solution.SimplexSolution{}, fmt.Errorf("StanfordAlgorithm: Failed to get ABasic matrix (%v)", err) } ABasicInv.Inverse(ABasic) var ABasicAe mat.VecDense @@ -263,7 +265,7 @@ func (algo *StanfordAlgorithm) Solve(initialState StanfordAlgorithmState) (probl } } if objectiveIsUnboundedBelow { - return problem.Solution{}, fmt.Errorf( + return simplex_solution.SimplexSolution{}, fmt.Errorf( "StanfordAlgorithm: Objective function is unbounded below, no solution exists at iteration %d", iter, ) @@ -274,13 +276,13 @@ func (algo *StanfordAlgorithm) Solve(initialState StanfordAlgorithmState) (probl // Compute the feasible Solution of the Basic variables xBasicII, err := algo.ComputeFeasibleBasicSolution(stateII) if err != nil { - return problem.Solution{}, err + return simplex_solution.SimplexSolution{}, err } // Compute the value of the objective function objII, err := algo.ComputeObjectiveFunctionValueWithFeasibleBasicSolution(stateII, xBasicII) if err != nil { - return problem.Solution{}, err + return simplex_solution.SimplexSolution{}, err } fmt.Printf("Iteration %d: Basic Solution: %v, Objective Value: %f\n", iter, xBasicII, objII) @@ -290,13 +292,13 @@ func (algo *StanfordAlgorithm) Solve(initialState StanfordAlgorithmState) (probl // Check if the solution is optimal if iter == algo.IterationLimit { - return problem.Solution{ + return simplex_solution.SimplexSolution{ Objective: objII, - Status: problem.OptimizationStatus_ITERATION_LIMIT, + Status: solution_status.ITERATION_LIMIT, }, nil } } - return problem.Solution{}, nil + return simplex_solution.SimplexSolution{}, nil } diff --git a/algorithms/tableau/state.go b/algorithms/tableau/state.go index 99a205f..a929e87 100644 --- a/algorithms/tableau/state.go +++ b/algorithms/tableau/state.go @@ -3,10 +3,11 @@ package tableau_algorithm1 import ( "fmt" - "github.com/MatProGo-dev/MatProInterface.go/problem" + solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" "github.com/MatProGo-dev/SymbolicMath.go/symbolic" "github.com/MatProGo-dev/simplex/algorithms" "github.com/MatProGo-dev/simplex/algorithms/tableau/selection" + simplex_solution "github.com/MatProGo-dev/simplex/solution" "github.com/MatProGo-dev/simplex/utils" "gonum.org/v1/gonum/mat" ) @@ -341,13 +342,13 @@ func (state *TableauAlgorithmState) CreateOptimalValuesMap() (map[uint64]float64 return solutionMap, nil } -func (state *TableauAlgorithmState) ToSolution(currentStatus problem.OptimizationStatus) problem.Solution { +func (state *TableauAlgorithmState) ToSolution(currentStatus solution_status.SolutionStatus) simplex_solution.SimplexSolution { // Construct Solution Map // Assemble Solution Output - return problem.Solution{ - Values: map[uint64]float64{}, - Objective: -1.0, - Status: currentStatus, + return simplex_solution.SimplexSolution{ + VariableValues: map[uint64]float64{}, + Objective: -1.0, + Status: currentStatus, } } diff --git a/algorithms/tableau/tableau_algo.go b/algorithms/tableau/tableau_algo.go index a2c25a6..30b3587 100644 --- a/algorithms/tableau/tableau_algo.go +++ b/algorithms/tableau/tableau_algo.go @@ -5,6 +5,7 @@ import ( "github.com/MatProGo-dev/MatProInterface.go/problem" tableau_termination "github.com/MatProGo-dev/simplex/algorithms/tableau/termination" + simplex_solution "github.com/MatProGo-dev/simplex/solution" "github.com/MatProGo-dev/simplex/utils" "gonum.org/v1/gonum/mat" ) @@ -33,13 +34,13 @@ func (algo *TableauAlgorithm) CheckTerminationConditions(state TableauAlgorithmS return tableau_termination.DidNotTerminate, nil } -func (algo *TableauAlgorithm) Solve(prob problem.OptimizationProblem) (problem.Solution, error) { +func (algo *TableauAlgorithm) Solve(prob problem.OptimizationProblem) (simplex_solution.SimplexSolution, error) { // Setup // Create initial Tableau state from the problem initialTableau, err := utils.GetInitialTableauFrom(&prob) if err != nil { - return problem.Solution{}, fmt.Errorf("there was an issue creating the initial tableau: %v", err) + return simplex_solution.SimplexSolution{}, fmt.Errorf("there was an issue creating the initial tableau: %v", err) } stateII := TableauAlgorithmState{ Tableau: &initialTableau, @@ -47,12 +48,12 @@ func (algo *TableauAlgorithm) Solve(prob problem.OptimizationProblem) (problem.S } // Loop - sol := problem.Solution{} + sol := simplex_solution.SimplexSolution{} for iter := 0; iter < algo.IterationLimit; iter++ { // Test for Termination condition, err := algo.CheckTerminationConditions(stateII) if err != nil { - return problem.Solution{}, + return simplex_solution.SimplexSolution{}, fmt.Errorf( "There was an issue checking the termination condition at iteration %v: %v", iter, @@ -70,7 +71,7 @@ func (algo *TableauAlgorithm) Solve(prob problem.OptimizationProblem) (problem.S err, ) } - sol.Values, err = stateII.CreateOptimalValuesMap() + sol.VariableValues, err = stateII.CreateOptimalValuesMap() if err != nil { return sol, fmt.Errorf( @@ -89,7 +90,7 @@ func (algo *TableauAlgorithm) Solve(prob problem.OptimizationProblem) (problem.S // Update the state stateII, err = stateII.CalculateNextState() if err != nil { - return problem.Solution{}, + return simplex_solution.SimplexSolution{}, fmt.Errorf( "There was an issue updating the state at iteration %v: %v", iter, diff --git a/algorithms/tableau/termination/termination_types.go b/algorithms/tableau/termination/termination_types.go index 0a3bb80..1cf15cd 100644 --- a/algorithms/tableau/termination/termination_types.go +++ b/algorithms/tableau/termination/termination_types.go @@ -1,7 +1,7 @@ package tableau_termination import ( - "github.com/MatProGo-dev/MatProInterface.go/problem" + solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" ) type TerminationType string @@ -10,15 +10,15 @@ const DidNotTerminate TerminationType = "Did Not Terminate" const MaximumIterationsReached TerminationType = "Maximum Iterations Reached" const OptimalSolutionFound TerminationType = "Optimal Solution Found" -func (tt TerminationType) ToOptimizationStatus() problem.OptimizationStatus { +func (tt TerminationType) ToOptimizationStatus() solution_status.SolutionStatus { switch tt { case DidNotTerminate: - return problem.OptimizationStatus_INPROGRESS + return solution_status.INPROGRESS case MaximumIterationsReached: - return problem.OptimizationStatus_ITERATION_LIMIT + return solution_status.ITERATION_LIMIT case OptimalSolutionFound: - return problem.OptimizationStatus_OPTIMAL + return solution_status.OPTIMAL default: - return problem.OptimizationStatus_INPROGRESS + return solution_status.INPROGRESS } } diff --git a/examples/gonum_bug1/try_bug.go b/examples/gonum_bug1/try_bug.go index 727c693..cf2bb7c 100644 --- a/examples/gonum_bug1/try_bug.go +++ b/examples/gonum_bug1/try_bug.go @@ -86,7 +86,7 @@ func main() { println("Solution Status: ", solutionMessage) println("Objective Value: ", solution.Objective) println("Variable Values: ") - for varName, varValue := range solution.Values { + for varName, varValue := range solution.VariableValues { println(" ", varName, ": ", varValue) } } diff --git a/examples/sergiy_butenko1/the_simplex_method_part_ii.go b/examples/sergiy_butenko1/the_simplex_method_part_ii.go index ba062a9..3d15c23 100644 --- a/examples/sergiy_butenko1/the_simplex_method_part_ii.go +++ b/examples/sergiy_butenko1/the_simplex_method_part_ii.go @@ -27,7 +27,7 @@ func main() { println("Solution Status: ", solutionMessage) println("Objective Value: ", solution.Objective) println("Variable Values: ") - for varName, varValue := range solution.Values { + for varName, varValue := range solution.VariableValues { println(" ", varName, ": ", varValue) } } diff --git a/go.mod b/go.mod index c08390e..18de501 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.0 toolchain go1.23.9 require ( - github.com/MatProGo-dev/MatProInterface.go v0.5.6 + github.com/MatProGo-dev/MatProInterface.go v0.6.0 github.com/MatProGo-dev/SymbolicMath.go v0.2.5 gonum.org/v1/gonum v0.16.0 ) diff --git a/go.sum b/go.sum index 168c097..f772359 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/MatProGo-dev/MatProInterface.go v0.5.6 h1:rzoT536J0sWQEJttc3vSsJ/ESgEg95NU2SbtaaGmUs4= github.com/MatProGo-dev/MatProInterface.go v0.5.6/go.mod h1:o/uWBdqnA6YXq0enVlFEwM6raLnV2xC0liXqRe8FrPA= +github.com/MatProGo-dev/MatProInterface.go v0.6.0 h1:x3hQwl5Hz1Z+ZuTlaQlMfdjvaQqjmc9agJkF7FIBR4U= +github.com/MatProGo-dev/MatProInterface.go v0.6.0/go.mod h1:o/uWBdqnA6YXq0enVlFEwM6raLnV2xC0liXqRe8FrPA= github.com/MatProGo-dev/SymbolicMath.go v0.2.5 h1:fGpwtywb2hUXvGKk1Te6PQEfHeVar5w05KTbc3wHj6A= github.com/MatProGo-dev/SymbolicMath.go v0.2.5/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= diff --git a/simplexSolver/solver.go b/simplexSolver/solver.go index e0c9fa4..4277a53 100644 --- a/simplexSolver/solver.go +++ b/simplexSolver/solver.go @@ -6,6 +6,7 @@ import ( "github.com/MatProGo-dev/MatProInterface.go/problem" "github.com/MatProGo-dev/simplex/algorithms" tableau_algorithm1 "github.com/MatProGo-dev/simplex/algorithms/tableau" + simplex_solution "github.com/MatProGo-dev/simplex/solution" ) type SimplexSolver struct { @@ -39,13 +40,13 @@ func (solver *SimplexSolver) CreateAlgorithm(algoType algorithms.AlgorithmType) } } -func (solver *SimplexSolver) Solve(prob problem.OptimizationProblem) (problem.Solution, error) { +func (solver *SimplexSolver) Solve(prob problem.OptimizationProblem) (simplex_solution.SimplexSolution, error) { // Setup // Choose Algorithm algo, err := solver.CreateAlgorithm(solver.Algorithm) if err != nil { - return problem.Solution{}, fmt.Errorf( + return simplex_solution.SimplexSolution{}, fmt.Errorf( "The Solve() function was given an unknown solver type: %v", solver.Algorithm, ) diff --git a/solution/simplex_solution.go b/solution/simplex_solution.go new file mode 100644 index 0000000..bced66b --- /dev/null +++ b/solution/simplex_solution.go @@ -0,0 +1,9 @@ +package simplex_solution + +import solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" + +type SimplexSolution struct { + VariableValues map[uint64]float64 + Objective float64 + Status solution_status.SolutionStatus +} From fb0ed9fc89da5fd30ae209169ed7c65692cb8f0b Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Sat, 4 Oct 2025 14:19:18 -0400 Subject: [PATCH 05/19] Added iterations field to SimplexSolution --- algorithms/tableau/state.go | 40 +++++++++++++++---- algorithms/tableau/tableau_algo.go | 17 ++------ examples/gonum_bug1/try_bug.go | 1 + .../the_simplex_method_part_ii.go | 1 + solution/simplex_solution.go | 1 + 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/algorithms/tableau/state.go b/algorithms/tableau/state.go index a929e87..19c381c 100644 --- a/algorithms/tableau/state.go +++ b/algorithms/tableau/state.go @@ -3,10 +3,10 @@ package tableau_algorithm1 import ( "fmt" - solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" "github.com/MatProGo-dev/SymbolicMath.go/symbolic" "github.com/MatProGo-dev/simplex/algorithms" "github.com/MatProGo-dev/simplex/algorithms/tableau/selection" + tableau_termination "github.com/MatProGo-dev/simplex/algorithms/tableau/termination" simplex_solution "github.com/MatProGo-dev/simplex/solution" "github.com/MatProGo-dev/simplex/utils" "gonum.org/v1/gonum/mat" @@ -342,13 +342,37 @@ func (state *TableauAlgorithmState) CreateOptimalValuesMap() (map[uint64]float64 return solutionMap, nil } -func (state *TableauAlgorithmState) ToSolution(currentStatus solution_status.SolutionStatus) simplex_solution.SimplexSolution { - // Construct Solution Map +func (state *TableauAlgorithmState) ToSolution(condition tableau_termination.TerminationType) (simplex_solution.SimplexSolution, error) { + // Create container for solution + var sol simplex_solution.SimplexSolution + var err error - // Assemble Solution Output - return simplex_solution.SimplexSolution{ - VariableValues: map[uint64]float64{}, - Objective: -1.0, - Status: currentStatus, + // Construct Solution Status + sol.Status = condition.ToOptimizationStatus() + + // Construct Iteration Count + sol.Iterations = state.IterationCount + + // Construct Objective Value + sol.Objective, err = state.CurrentObjectiveValue() + if err != nil { + return sol, + fmt.Errorf( + "There was an issue getting the objective value at termination: %v", + err, + ) } + + // Construct Variable map + sol.VariableValues, err = state.CreateOptimalValuesMap() + if err != nil { + return sol, + fmt.Errorf( + "There was an issue creating the optimal values map at termination: %v", + err, + ) + } + + // Assemble Solution Output + return sol, nil } diff --git a/algorithms/tableau/tableau_algo.go b/algorithms/tableau/tableau_algo.go index 30b3587..ad6e8aa 100644 --- a/algorithms/tableau/tableau_algo.go +++ b/algorithms/tableau/tableau_algo.go @@ -62,24 +62,15 @@ func (algo *TableauAlgorithm) Solve(prob problem.OptimizationProblem) (simplex_s } if condition != tableau_termination.DidNotTerminate { - sol.Status = condition.ToOptimizationStatus() - sol.Objective, err = stateII.CurrentObjectiveValue() + sol, err = stateII.ToSolution(condition) if err != nil { - return sol, + return simplex_solution.SimplexSolution{}, fmt.Errorf( - "There was an issue getting the objective value at termination: %v", + "There was an issue converting the final state to a solution at iteration %v: %v", + iter, err, ) } - sol.VariableValues, err = stateII.CreateOptimalValuesMap() - if err != nil { - return sol, - fmt.Errorf( - "There was an issue creating the optimal values map at termination: %v", - err, - ) - } - // Exit the loop break } diff --git a/examples/gonum_bug1/try_bug.go b/examples/gonum_bug1/try_bug.go index cf2bb7c..a7f6f29 100644 --- a/examples/gonum_bug1/try_bug.go +++ b/examples/gonum_bug1/try_bug.go @@ -85,6 +85,7 @@ func main() { solutionMessage, _ := solution.Status.ToMessage() println("Solution Status: ", solutionMessage) println("Objective Value: ", solution.Objective) + println("Number of Iterations: ", solution.Iterations) println("Variable Values: ") for varName, varValue := range solution.VariableValues { println(" ", varName, ": ", varValue) diff --git a/examples/sergiy_butenko1/the_simplex_method_part_ii.go b/examples/sergiy_butenko1/the_simplex_method_part_ii.go index 3d15c23..d9eed9d 100644 --- a/examples/sergiy_butenko1/the_simplex_method_part_ii.go +++ b/examples/sergiy_butenko1/the_simplex_method_part_ii.go @@ -26,6 +26,7 @@ func main() { solutionMessage, _ := solution.Status.ToMessage() println("Solution Status: ", solutionMessage) println("Objective Value: ", solution.Objective) + println("Number of Iterations: ", solution.Iterations) println("Variable Values: ") for varName, varValue := range solution.VariableValues { println(" ", varName, ": ", varValue) diff --git a/solution/simplex_solution.go b/solution/simplex_solution.go index bced66b..e6db9f5 100644 --- a/solution/simplex_solution.go +++ b/solution/simplex_solution.go @@ -6,4 +6,5 @@ type SimplexSolution struct { VariableValues map[uint64]float64 Objective float64 Status solution_status.SolutionStatus + Iterations int } From 4096194d2259f278b839cd1bf6be4b9572b66809 Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Sat, 4 Oct 2025 14:45:45 -0400 Subject: [PATCH 06/19] Improved the documentation of the `SimplexSolution` Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- solution/simplex_solution.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/solution/simplex_solution.go b/solution/simplex_solution.go index bced66b..0cbebaa 100644 --- a/solution/simplex_solution.go +++ b/solution/simplex_solution.go @@ -2,8 +2,14 @@ package simplex_solution import solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" +// SimplexSolution represents the result of solving a linear program using the simplex method. +// It contains the values of the decision variables, the objective value, and the solution status. type SimplexSolution struct { + // VariableValues maps variable IDs (as uint64) to their solution values. + // The uint64 key typically represents the unique identifier or index of a variable in the model. VariableValues map[uint64]float64 + // Objective is the value of the objective function at the solution. Objective float64 + // Status indicates the status of the solution (e.g., optimal, infeasible). Status solution_status.SolutionStatus } From 4ea1230c35c04c2d37f2ecb73add11fbb30c990b Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Sat, 4 Oct 2025 14:46:10 -0400 Subject: [PATCH 07/19] Remove commented code Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- algorithms/tableau/state.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/tableau/state.go b/algorithms/tableau/state.go index a929e87..395ca55 100644 --- a/algorithms/tableau/state.go +++ b/algorithms/tableau/state.go @@ -289,7 +289,7 @@ func (state *TableauAlgorithmState) CalculateOptimalSolution() (mat.VecDense, er // - The non-basic variables set to zero A, b := state.A(), state.B() numConstraints, _ := A.Dims() - numNonBasic := state.Tableau.NumberOfNonBasicVariables() //state.NumberOfVariables() - state.NumberOfConstraints() + numNonBasic := state.Tableau.NumberOfNonBasicVariables() // Augment the A and b matrices with the non-basic variable constraints AAugmented := mat.NewDense(numConstraints+numNonBasic, numVars, nil) From e9b2b4dfda8ed3b4e5448f85c148463061b73af1 Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Sat, 4 Oct 2025 14:47:17 -0400 Subject: [PATCH 08/19] Tried to debug the new example --- algorithms/tableau/state.go | 8 +++----- examples/gonum_bug1/try_bug.go | 8 ++++++++ utils/tableau.go | 2 ++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/algorithms/tableau/state.go b/algorithms/tableau/state.go index 19c381c..53d9c33 100644 --- a/algorithms/tableau/state.go +++ b/algorithms/tableau/state.go @@ -297,16 +297,14 @@ func (state *TableauAlgorithmState) CalculateOptimalSolution() (mat.VecDense, er bAugmented := mat.NewVecDense(numConstraints+numNonBasic, nil) bAugmented.CopyVec(b) - fmt.Println("A: ", mat.Formatted(AAugmented)) - // Add the non-basic variable constraints nonBasicVars := state.GetNonBasicVariables() for ii, v := range nonBasicVars { - fmt.Println("Adding non-basic variable constraint for variable: ", v) + // fmt.Println("Adding non-basic variable constraint for variable: ", v) // Find the index of the variable in the tableau vIdxInTableau, _ := symbolic.FindInSlice(v, state.Tableau.Variables) - fmt.Println("vIdxInTableau: ", vIdxInTableau) - fmt.Println("Targeted row: ", numConstraints+ii) + // fmt.Println("vIdxInTableau: ", vIdxInTableau) + // fmt.Println("Targeted row: ", numConstraints+ii) AAugmented.Set(numConstraints+ii, vIdxInTableau, 1.0) } // b is already zero in the new rows, so we don't need to set anything in bAugmented diff --git a/examples/gonum_bug1/try_bug.go b/examples/gonum_bug1/try_bug.go index a7f6f29..56d8bb8 100644 --- a/examples/gonum_bug1/try_bug.go +++ b/examples/gonum_bug1/try_bug.go @@ -4,6 +4,7 @@ import ( "github.com/MatProGo-dev/MatProInterface.go/problem" getKMatrix "github.com/MatProGo-dev/SymbolicMath.go/get/KMatrix" getKVector "github.com/MatProGo-dev/SymbolicMath.go/get/KVector" + "github.com/MatProGo-dev/SymbolicMath.go/symbolic" "github.com/MatProGo-dev/simplex/simplexSolver" "gonum.org/v1/gonum/mat" ) @@ -90,4 +91,11 @@ func main() { for varName, varValue := range solution.VariableValues { println(" ", varName, ": ", varValue) } + + // Construct Variable Values map in terms of map[symbolic.Variable] float64 + varValues := make(map[symbolic.Variable]float64) + for varID, varValue := range solution.VariableValues { + // Extract variable form problem that has the same ID + varValues[symbolic.NewVariable(varName)] = varValue + } } diff --git a/utils/tableau.go b/utils/tableau.go index 6562ae6..6bd892f 100644 --- a/utils/tableau.go +++ b/utils/tableau.go @@ -446,6 +446,8 @@ func (tableau *Tableau) CanNotBeImproved() bool { // Get the coefficients of the non-basic variables c := tableau.C() + fmt.Println("c =", c) + // Check if all coefficients are less than or equal to zero for ii := 0; ii < c.Len(); ii++ { if c.AtVec(ii) < 0 { From 16d1b2a88f9d0f4cd81ffcd4e709bbd3e5766ea2 Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Sat, 4 Oct 2025 14:47:48 -0400 Subject: [PATCH 09/19] Cleaning up unused code in example --- examples/gonum_bug1/try_bug.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/examples/gonum_bug1/try_bug.go b/examples/gonum_bug1/try_bug.go index 56d8bb8..a7f6f29 100644 --- a/examples/gonum_bug1/try_bug.go +++ b/examples/gonum_bug1/try_bug.go @@ -4,7 +4,6 @@ import ( "github.com/MatProGo-dev/MatProInterface.go/problem" getKMatrix "github.com/MatProGo-dev/SymbolicMath.go/get/KMatrix" getKVector "github.com/MatProGo-dev/SymbolicMath.go/get/KVector" - "github.com/MatProGo-dev/SymbolicMath.go/symbolic" "github.com/MatProGo-dev/simplex/simplexSolver" "gonum.org/v1/gonum/mat" ) @@ -91,11 +90,4 @@ func main() { for varName, varValue := range solution.VariableValues { println(" ", varName, ": ", varValue) } - - // Construct Variable Values map in terms of map[symbolic.Variable] float64 - varValues := make(map[symbolic.Variable]float64) - for varID, varValue := range solution.VariableValues { - // Extract variable form problem that has the same ID - varValues[symbolic.NewVariable(varName)] = varValue - } } From 6df1ba7f38597c340d4d29ee0618463dd0385580 Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Wed, 15 Oct 2025 20:52:54 -0400 Subject: [PATCH 10/19] Upgraded MatProInterface.go interface --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 18de501..a602e97 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.0 toolchain go1.23.9 require ( - github.com/MatProGo-dev/MatProInterface.go v0.6.0 - github.com/MatProGo-dev/SymbolicMath.go v0.2.5 + github.com/MatProGo-dev/MatProInterface.go v0.6.4 + github.com/MatProGo-dev/SymbolicMath.go v0.2.6 gonum.org/v1/gonum v0.16.0 ) diff --git a/go.sum b/go.sum index f772359..48fd2a7 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ -github.com/MatProGo-dev/MatProInterface.go v0.5.6 h1:rzoT536J0sWQEJttc3vSsJ/ESgEg95NU2SbtaaGmUs4= -github.com/MatProGo-dev/MatProInterface.go v0.5.6/go.mod h1:o/uWBdqnA6YXq0enVlFEwM6raLnV2xC0liXqRe8FrPA= -github.com/MatProGo-dev/MatProInterface.go v0.6.0 h1:x3hQwl5Hz1Z+ZuTlaQlMfdjvaQqjmc9agJkF7FIBR4U= -github.com/MatProGo-dev/MatProInterface.go v0.6.0/go.mod h1:o/uWBdqnA6YXq0enVlFEwM6raLnV2xC0liXqRe8FrPA= -github.com/MatProGo-dev/SymbolicMath.go v0.2.5 h1:fGpwtywb2hUXvGKk1Te6PQEfHeVar5w05KTbc3wHj6A= -github.com/MatProGo-dev/SymbolicMath.go v0.2.5/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU= +github.com/MatProGo-dev/MatProInterface.go v0.6.2 h1:DSHXN5OLtYUfBUx41jSkhIitZwfJ3VabmttP7eDCLQ0= +github.com/MatProGo-dev/MatProInterface.go v0.6.2/go.mod h1:v7e1RkEpIX5F2l/AeDy04CCaVERBA7vGI8rjVItB3dc= +github.com/MatProGo-dev/MatProInterface.go v0.6.4 h1:tjoDJMmAelPVXz7gZcdUJyLYpSd2Xb9Pbqlb5FOQmTc= +github.com/MatProGo-dev/MatProInterface.go v0.6.4/go.mod h1:v7e1RkEpIX5F2l/AeDy04CCaVERBA7vGI8rjVItB3dc= +github.com/MatProGo-dev/SymbolicMath.go v0.2.6 h1:0THkOKIjdjadIb9MHIUflk08U7tv17KvtQPOP3eMOfk= +github.com/MatProGo-dev/SymbolicMath.go v0.2.6/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= From b3d2996dd4e645bbe7b05b2617414909508882d0 Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Wed, 15 Oct 2025 20:53:35 -0400 Subject: [PATCH 11/19] Upgraded usage of modified methods throughout simplex --- algorithms/tableau/state.go | 62 ++++++++++++++--------- algorithms/tableau/tableau_algo.go | 4 +- solution/simplex_solution.go | 30 +++++++++-- testing/algorithms/stanford/state_test.go | 6 +-- testing/algorithms/tableau/state_test.go | 3 +- testing/utils/tableau_test.go | 4 +- 6 files changed, 73 insertions(+), 36 deletions(-) diff --git a/algorithms/tableau/state.go b/algorithms/tableau/state.go index 9fbd128..fe9a0e5 100644 --- a/algorithms/tableau/state.go +++ b/algorithms/tableau/state.go @@ -3,6 +3,8 @@ package tableau_algorithm1 import ( "fmt" + "github.com/MatProGo-dev/MatProInterface.go/problem" + "github.com/MatProGo-dev/MatProInterface.go/solution" "github.com/MatProGo-dev/SymbolicMath.go/symbolic" "github.com/MatProGo-dev/simplex/algorithms" "github.com/MatProGo-dev/simplex/algorithms/tableau/selection" @@ -91,17 +93,6 @@ func (state *TableauAlgorithmState) CheckTerminationCondition() (bool, error) { return true, nil } -func (state *TableauAlgorithmState) CurrentObjectiveValue() (float64, error) { - // Input Checking - err := state.Check() - if err != nil { - return 0.0, err - } - - // Setup - return state.Tableau.D(), nil -} - /* GetBasicVariables Description: @@ -251,6 +242,8 @@ func (state *TableauAlgorithmState) CalculateNextState() (TableauAlgorithmState, return TableauAlgorithmState{}, err } + // fmt.Println("Calculating next state from tableau:", mat.Formatted(state.Tableau.AsCompressedMatrix)) + // Select the pivot column and row (i.e., the entering and exiting variables in the tableau) // Here, we use Bland's Rule to select the entering variable // TODO(Kwesi): Make other rules available @@ -260,6 +253,9 @@ func (state *TableauAlgorithmState) CalculateNextState() (TableauAlgorithmState, return TableauAlgorithmState{}, fmt.Errorf("TableauAlgorithmState: Failed to select entering and exiting variables (%v)", err) } + // fmt.Println("Entering variable index: ", enteringVarIdx, " (", state.Tableau.Variables[enteringVarIdx], ")") + // fmt.Println("Exiting variable index: ", exitingVarIdx, " (", state.Tableau.Variables[exitingVarIdx], ")") + // Create the new tableau newTab, err := state.Tableau.Pivot(enteringVarIdx, exitingVarIdx) if err != nil { @@ -318,7 +314,7 @@ func (state *TableauAlgorithmState) CalculateOptimalSolution() (mat.VecDense, er return *solutionVec, nil } -func (state *TableauAlgorithmState) CreateOptimalValuesMap() (map[uint64]float64, error) { +func (state *TableauAlgorithmState) CreateOptimalValuesMap(originalVariablesAsStandardFormExpressions map[symbolic.Variable]symbolic.Expression) (map[uint64]float64, error) { // Input Checking err := state.Check() if err != nil { @@ -331,16 +327,33 @@ func (state *TableauAlgorithmState) CreateOptimalValuesMap() (map[uint64]float64 return nil, err } - // Create the map - solutionMap := map[uint64]float64{} + // Create the map between the STANDARD FORM variables and the optimal values + standardFormOptimalValues := map[symbolic.Variable]symbolic.Expression{} for ii, v := range state.Tableau.Variables { - solutionMap[v.ID] = solutionVec.AtVec(ii) + standardFormOptimalValues[v] = symbolic.K(solutionVec.AtVec(ii)) + } + + // Create the map between the ORIGINAL variables and the optimal values + optimalValueMap := map[uint64]float64{} + for origVar, expr := range originalVariablesAsStandardFormExpressions { + // Evaluate the expression (which is equal to the original variable) using the solution map + value := expr.SubstituteAccordingTo(standardFormOptimalValues) + valAsK, ok := value.(symbolic.K) + if !ok { + return nil, fmt.Errorf("TableauAlgorithmState: Failed to evaluate optimal value for original variable %v", origVar) + } + // Add the value to the output map + optimalValueMap[origVar.ID] = float64(valAsK) } - return solutionMap, nil + return optimalValueMap, nil } -func (state *TableauAlgorithmState) ToSolution(condition tableau_termination.TerminationType) (simplex_solution.SimplexSolution, error) { +func (state *TableauAlgorithmState) ToSolution( + condition tableau_termination.TerminationType, + varMap map[symbolic.Variable]symbolic.Expression, + originalProblem *problem.OptimizationProblem, +) (simplex_solution.SimplexSolution, error) { // Create container for solution var sol simplex_solution.SimplexSolution var err error @@ -351,22 +364,25 @@ func (state *TableauAlgorithmState) ToSolution(condition tableau_termination.Ter // Construct Iteration Count sol.Iterations = state.IterationCount - // Construct Objective Value - sol.Objective, err = state.CurrentObjectiveValue() + // Attach original problem + sol.OriginalProblem = originalProblem + + // Construct Variable map + sol.VariableValues, err = state.CreateOptimalValuesMap(varMap) if err != nil { return sol, fmt.Errorf( - "There was an issue getting the objective value at termination: %v", + "There was an issue creating the optimal values map at termination: %v", err, ) } - // Construct Variable map - sol.VariableValues, err = state.CreateOptimalValuesMap() + // Construct Objective Value + sol.Objective, err = solution.GetOptimalObjectiveValue(&sol) if err != nil { return sol, fmt.Errorf( - "There was an issue creating the optimal values map at termination: %v", + "There was an issue getting the objective value at termination: %v", err, ) } diff --git a/algorithms/tableau/tableau_algo.go b/algorithms/tableau/tableau_algo.go index ad6e8aa..fbd472c 100644 --- a/algorithms/tableau/tableau_algo.go +++ b/algorithms/tableau/tableau_algo.go @@ -38,7 +38,7 @@ func (algo *TableauAlgorithm) Solve(prob problem.OptimizationProblem) (simplex_s // Setup // Create initial Tableau state from the problem - initialTableau, err := utils.GetInitialTableauFrom(&prob) + initialTableau, mapFromOriginalVariablesToStandardFormVariables, err := utils.GetInitialTableauFrom(&prob) if err != nil { return simplex_solution.SimplexSolution{}, fmt.Errorf("there was an issue creating the initial tableau: %v", err) } @@ -62,7 +62,7 @@ func (algo *TableauAlgorithm) Solve(prob problem.OptimizationProblem) (simplex_s } if condition != tableau_termination.DidNotTerminate { - sol, err = stateII.ToSolution(condition) + sol, err = stateII.ToSolution(condition, mapFromOriginalVariablesToStandardFormVariables, &prob) if err != nil { return simplex_solution.SimplexSolution{}, fmt.Errorf( diff --git a/solution/simplex_solution.go b/solution/simplex_solution.go index 1b76829..403b5d6 100644 --- a/solution/simplex_solution.go +++ b/solution/simplex_solution.go @@ -1,6 +1,9 @@ package simplex_solution -import solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" +import ( + "github.com/MatProGo-dev/MatProInterface.go/problem" + solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" +) // SimplexSolution represents the result of solving a linear program using the simplex method. // It contains the values of the decision variables, the objective value, and the solution status. @@ -9,8 +12,27 @@ type SimplexSolution struct { // The uint64 key typically represents the unique identifier or index of a variable in the model. VariableValues map[uint64]float64 // Objective is the value of the objective function at the solution. - Objective float64 + Objective float64 // Status indicates the status of the solution (e.g., optimal, infeasible). - Status solution_status.SolutionStatus - Iterations int + Status solution_status.SolutionStatus + Iterations int + // originalProblem is the original optimization problem that was solved to obtain this solution. + // It is included for reference and may be nil if not applicable. + OriginalProblem *problem.OptimizationProblem +} + +func (sol *SimplexSolution) GetValueMap() map[uint64]float64 { + return sol.VariableValues +} + +func (sol *SimplexSolution) GetOptimalValue() float64 { + return sol.Objective +} + +func (sol *SimplexSolution) GetStatus() solution_status.SolutionStatus { + return sol.Status +} + +func (sol *SimplexSolution) GetProblem() *problem.OptimizationProblem { + return sol.OriginalProblem } diff --git a/testing/algorithms/stanford/state_test.go b/testing/algorithms/stanford/state_test.go index 721995f..30bf0e5 100644 --- a/testing/algorithms/stanford/state_test.go +++ b/testing/algorithms/stanford/state_test.go @@ -16,7 +16,7 @@ func TestStanfordAlgorithmState_NonBasicVariables1(t *testing.T) { exampleProblem1 := examples.GetTestProblem1() // Create the problem in standard form - problemInStandardForm, slackVariables, err := exampleProblem1.ToLPStandardForm1() + problemInStandardForm, slackVariables, _, err := exampleProblem1.ToLPStandardForm1() if err != nil { t.Errorf("Expected no error, but got: %v", err) } @@ -80,7 +80,7 @@ func TestStanfordAlgorithmState_BasicVariables1(t *testing.T) { exampleProblem1 := examples.GetTestProblem1() // Create the problem in standard form - problemInStandardForm, slackVariables, err := exampleProblem1.ToLPStandardForm1() + problemInStandardForm, slackVariables, _, err := exampleProblem1.ToLPStandardForm1() if err != nil { t.Errorf("Expected no error, but got: %v", err) } @@ -147,7 +147,7 @@ func TestStanfordAlgorithmState_ReducedCostVector1(t *testing.T) { exampleProblem1 := examples.GetTestProblem2() // Create the problem in standard form - problemInStandardForm, slackVariables, err := exampleProblem1.ToLPStandardForm1() + problemInStandardForm, slackVariables, _, err := exampleProblem1.ToLPStandardForm1() if err != nil { t.Errorf("Expected no error, but got: %v", err) } diff --git a/testing/algorithms/tableau/state_test.go b/testing/algorithms/tableau/state_test.go index de7d526..4d8c7a7 100644 --- a/testing/algorithms/tableau/state_test.go +++ b/testing/algorithms/tableau/state_test.go @@ -34,7 +34,7 @@ func TestTableau_CalculateOptimalSolution1(t *testing.T) { // Use the optimization solver to solve the problem // Create initial Tableau state from the problem - initialTableau, err := utils.GetInitialTableauFrom(testProblem) + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) if err != nil { t.Errorf("there was an issue creating the initial tableau: %v", err) } @@ -66,5 +66,4 @@ func TestTableau_CalculateOptimalSolution1(t *testing.T) { t.Errorf("Expected solution value %v at index %d, but got %v", val, ii, solVec.AtVec(ii)) } } - } diff --git a/testing/utils/tableau_test.go b/testing/utils/tableau_test.go index 64740c1..2803efe 100644 --- a/testing/utils/tableau_test.go +++ b/testing/utils/tableau_test.go @@ -24,7 +24,7 @@ func TestGetInitialTableau1(t *testing.T) { problemIn := examples.GetTestProblem3() // Create the tableau using the initial state + problem in standard form - tableau, err := utils.GetInitialTableauFrom(problemIn) + tableau, _, err := utils.GetInitialTableauFrom(problemIn) if err != nil { t.Errorf("Expected no error, but got: %v", err) } @@ -83,7 +83,7 @@ func TestComputeFeasibleSolution1(t *testing.T) { problemIn := examples.GetTestProblem3() // Create the tableau - tableau, err := utils.GetInitialTableauFrom(problemIn) + tableau, _, err := utils.GetInitialTableauFrom(problemIn) if err != nil { t.Errorf("Expected no error, but got: %v", err) } From aca9aa1c6e4352f75001a48663fcb59e34f72d65 Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Wed, 15 Oct 2025 20:53:47 -0400 Subject: [PATCH 12/19] Fixing bug in SimplexMethod Tableau method --- algorithms/tableau/selection/blands_rule.go | 5 +++-- examples/gonum_bug1/try_bug.go | 2 +- utils/tableau.go | 16 +++++++++------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/algorithms/tableau/selection/blands_rule.go b/algorithms/tableau/selection/blands_rule.go index 8cf3821..f901d67 100644 --- a/algorithms/tableau/selection/blands_rule.go +++ b/algorithms/tableau/selection/blands_rule.go @@ -3,6 +3,7 @@ package selection import ( "fmt" + "github.com/MatProGo-dev/SymbolicMath.go/symbolic" "github.com/MatProGo-dev/simplex/utils" ) @@ -55,7 +56,7 @@ Description: func (br BlandsRule) SelectExitingVariable(tableau utils.Tableau, enteringVarIdx int) int { // Setup minIndex := -1 - minRatio := -1.0 + minRatio := float64(symbolic.Infinity) // Get the relevant matrices A := tableau.A() @@ -74,7 +75,7 @@ func (br BlandsRule) SelectExitingVariable(tableau utils.Tableau, enteringVarIdx // Iterate through the ratios and find the smallest one for i, ratio := range ratios { if ratio >= 0 { // Only consider valid ratios - if minRatio < 0 || ratio < minRatio || (ratio == minRatio && tableau.BasicVariableIndicies[i] < tableau.BasicVariableIndicies[minIndex]) { + if ratio < minRatio || (ratio == minRatio && tableau.BasicVariableIndicies[i] < tableau.BasicVariableIndicies[minIndex]) { minRatio = ratio minIndex = i } diff --git a/examples/gonum_bug1/try_bug.go b/examples/gonum_bug1/try_bug.go index a7f6f29..6545d10 100644 --- a/examples/gonum_bug1/try_bug.go +++ b/examples/gonum_bug1/try_bug.go @@ -56,7 +56,7 @@ func BuildOptimizationProblem() problem.OptimizationProblem { []float64{3370, 1031, 2350, 2289, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, ) Gbuf := []float64{1, 0, 0, 1, 1, 0, 2, 2, 0, 2, 0, 0, 1, 0, 8, 1, 0, 0, 8, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 2, 0, 0, 1, 0, 8, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 8, 0, 8, 1, 0, 0, 1, 8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1} - G := mat.NewDense(6+varCount, varCount, Gbuf) + G := mat.NewDense(63, varCount, Gbuf) out.Constraints = append( out.Constraints, diff --git a/utils/tableau.go b/utils/tableau.go index 6bd892f..b3188ea 100644 --- a/utils/tableau.go +++ b/utils/tableau.go @@ -348,28 +348,30 @@ Description: This function computes the initial tableau of an */ -func GetInitialTableauFrom(problemIn *problem.OptimizationProblem) (Tableau, error) { +func GetInitialTableauFrom(problemIn *problem.OptimizationProblem) (Tableau, map[symbolic.Variable]symbolic.Expression, error) { // Input Processing if problemIn == nil { - return Tableau{}, fmt.Errorf( + return Tableau{}, nil, fmt.Errorf( "Check: tableau.Problem cannot be nil", ) } // Ensure that the problem is a linear program if !problemIn.IsLinear() { - return Tableau{}, fmt.Errorf( + return Tableau{}, nil, fmt.Errorf( "Check: the problem is not a linear program", ) } // Transform the problem into the standard form where all constraints // are equality constraints - problemInStandardForm, slackVariables, err := problemIn.ToLPStandardForm2() + problemInStandardForm, slackVariables, mapFromOriginalVariablesToNewExpressions, err := problemIn.ToLPStandardForm2() if err != nil { - return Tableau{}, err + return Tableau{}, nil, err } + fmt.Println("Problem in standard form:", problemInStandardForm) + // Transform SlackVariables object into indicies var slackVariableIndicies []int for _, slackVar := range slackVariables { @@ -381,7 +383,7 @@ func GetInitialTableauFrom(problemIn *problem.OptimizationProblem) (Tableau, err // [ A | b ] A, b, err := problemInStandardForm.LinearEqualityConstraintMatrices() if err != nil { - return Tableau{}, err + return Tableau{}, mapFromOriginalVariablesToNewExpressions, err } Ab := symbolic.HStack(A, b) @@ -408,7 +410,7 @@ func GetInitialTableauFrom(problemIn *problem.OptimizationProblem) (Tableau, err AsCompressedMatrix: &tableauMatCondensedAsDense, Variables: problemInStandardForm.Variables, BasicVariableIndicies: slackVariableIndicies, - }, nil + }, mapFromOriginalVariablesToNewExpressions, nil } /* From 941a32296112f5b56053746980a6ff4ee1275970 Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Wed, 15 Oct 2025 21:26:24 -0400 Subject: [PATCH 13/19] Added working box example --- algorithms/tableau/selection/blands_rule.go | 2 + examples/box1/box.go | 82 +++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 examples/box1/box.go diff --git a/algorithms/tableau/selection/blands_rule.go b/algorithms/tableau/selection/blands_rule.go index f901d67..0aaa3cc 100644 --- a/algorithms/tableau/selection/blands_rule.go +++ b/algorithms/tableau/selection/blands_rule.go @@ -99,6 +99,8 @@ func (br BlandsRule) SelectEnteringAndExitingVariables(tableau utils.Tableau) (i return -1, -1, nil // Optimal solution found, no entering variable } + fmt.Println("Entering variable index:", enteringVarIdx) + // Select the exiting variable exitingVarIdx := br.SelectExitingVariable(tableau, enteringVarIdx) if exitingVarIdx == -1 { diff --git a/examples/box1/box.go b/examples/box1/box.go new file mode 100644 index 0000000..9780d98 --- /dev/null +++ b/examples/box1/box.go @@ -0,0 +1,82 @@ +package main + +import ( + "github.com/MatProGo-dev/MatProInterface.go/problem" + getKVector "github.com/MatProGo-dev/SymbolicMath.go/get/KVector" + "github.com/MatProGo-dev/SymbolicMath.go/symbolic" + "github.com/MatProGo-dev/simplex/simplexSolver" +) + +/* +Description: + + This function builds an optimization problem where we attempt to find + the optimal solution to a linear programming problem that is in a feasible + region that is a box. + + The problem will be: + + Minimize: x1 + 2*x2 + Subject to: + 0 <= x1 <= 1 + 0 <= x2 <= 1 + + The optimal solution is x1 = 0, x2 = 0 with an objective value of 0. +*/ +func BuildOptimizationProblem() problem.OptimizationProblem { + // setup + varCount := 2 + out := problem.NewProblem("Box LP Problem") + + // Create the variables + x := out.AddVariableVector(varCount) + + // Create the objective + c := getKVector.From( + []float64{1, 2}, + ) + out.SetObjective( + c.Transpose().Multiply(x), + problem.SenseMinimize, + ) + + // Create the constraints + // - x >= 0 + out.Constraints = append( + out.Constraints, + x.GreaterEq(symbolic.ZerosVector(varCount)), + ) + + // - x <= 1 + out.Constraints = append( + out.Constraints, + x.LessEq(symbolic.OnesVector(varCount)), + ) + + return *out +} + +func main() { + // This is just a placeholder to make the package "main" valid. + trickyProblem := BuildOptimizationProblem() + + // Use solver to solve the problem + solver := simplexSolver.New("Simplex Solver Example") + solver.IterationLimit = 100 + + // Solve the problem + solution, err := solver.Solve(trickyProblem) + if err != nil { + panic(err) + } + + // Print the solution + solutionMessage, _ := solution.Status.ToMessage() + println("Solution Status: ", solutionMessage) + println("Objective Value: ", solution.Objective) + println("Number of Iterations: ", solution.Iterations) + println("Variable Values: ") + for varName, varValue := range solution.VariableValues { + println(" ", varName, ": ", varValue) + } +} From e0f2023d03db9caf5a32bc291169de5d4d0e64d7 Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Wed, 15 Oct 2025 21:33:39 -0400 Subject: [PATCH 14/19] remove references to old MatProInterface.go --- go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.sum b/go.sum index 48fd2a7..7e87577 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/MatProGo-dev/MatProInterface.go v0.6.2 h1:DSHXN5OLtYUfBUx41jSkhIitZwfJ3VabmttP7eDCLQ0= -github.com/MatProGo-dev/MatProInterface.go v0.6.2/go.mod h1:v7e1RkEpIX5F2l/AeDy04CCaVERBA7vGI8rjVItB3dc= github.com/MatProGo-dev/MatProInterface.go v0.6.4 h1:tjoDJMmAelPVXz7gZcdUJyLYpSd2Xb9Pbqlb5FOQmTc= github.com/MatProGo-dev/MatProInterface.go v0.6.4/go.mod h1:v7e1RkEpIX5F2l/AeDy04CCaVERBA7vGI8rjVItB3dc= github.com/MatProGo-dev/SymbolicMath.go v0.2.6 h1:0THkOKIjdjadIb9MHIUflk08U7tv17KvtQPOP3eMOfk= From c58b3b9fef183e9fc869ef2f0bd03a665edc43ec Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Wed, 15 Oct 2025 21:37:05 -0400 Subject: [PATCH 15/19] Updated README.md --- README.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b7642d..5dde69e 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,80 @@ go get github.com/MatProGo-dev/simplex # Usage -TBD \ No newline at end of file +``` +/* +Description: + + This function builds an optimization problem where we attempt to find + the optimal solution to a linear programming problem that is in a feasible + region that is a box. + + The problem will be: + + Minimize: x1 + 2*x2 + Subject to: + 0 <= x1 <= 1 + 0 <= x2 <= 1 + + The optimal solution is x1 = 0, x2 = 0 with an objective value of 0. +*/ +func BuildOptimizationProblem() problem.OptimizationProblem { + // setup + varCount := 2 + out := problem.NewProblem("Box LP Problem") + + // Create the variables + x := out.AddVariableVector(varCount) + + // Create the objective + c := getKVector.From( + []float64{1, 2}, + ) + out.SetObjective( + c.Transpose().Multiply(x), + problem.SenseMinimize, + ) + + // Create the constraints + // - x >= 0 + out.Constraints = append( + out.Constraints, + x.GreaterEq(symbolic.ZerosVector(varCount)), + ) + + // - x <= 1 + out.Constraints = append( + out.Constraints, + x.LessEq(symbolic.OnesVector(varCount)), + ) + + return *out +} + +func main() { + // This is just a placeholder to make the package "main" valid. + trickyProblem := BuildOptimizationProblem() + + // Use solver to solve the problem + solver := simplexSolver.New("Simplex Solver Example") + solver.IterationLimit = 100 + + // Solve the problem + solution, err := solver.Solve(trickyProblem) + if err != nil { + panic(err) + } + + // Print the solution + solutionMessage, _ := solution.Status.ToMessage() + println("Solution Status: ", solutionMessage) + println("Objective Value: ", solution.Objective) + println("Number of Iterations: ", solution.Iterations) + println("Variable Values: ") + for varName, varValue := range solution.VariableValues { + println(" ", varName, ": ", varValue) + } +} +``` + +See the examples directory for more example use cases for the library. \ No newline at end of file From 1882ae9d909b18608c33cbddc034577c6f6fcdea Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Wed, 15 Oct 2025 21:37:59 -0400 Subject: [PATCH 16/19] Updated README.md example --- README.md | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 5dde69e..264dec3 100644 --- a/README.md +++ b/README.md @@ -11,22 +11,15 @@ go get github.com/MatProGo-dev/simplex # Usage ``` -/* -Description: +package main - This function builds an optimization problem where we attempt to find - the optimal solution to a linear programming problem that is in a feasible - region that is a box. +import ( + "github.com/MatProGo-dev/MatProInterface.go/problem" + getKVector "github.com/MatProGo-dev/SymbolicMath.go/get/KVector" + "github.com/MatProGo-dev/SymbolicMath.go/symbolic" + "github.com/MatProGo-dev/simplex/simplexSolver" +) - The problem will be: - - Minimize: x1 + 2*x2 - Subject to: - 0 <= x1 <= 1 - 0 <= x2 <= 1 - - The optimal solution is x1 = 0, x2 = 0 with an objective value of 0. -*/ func BuildOptimizationProblem() problem.OptimizationProblem { // setup varCount := 2 From ccc5f8ae3b0fe9f803b28ef606f66c18210d0645 Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Fri, 17 Oct 2025 00:04:14 -0400 Subject: [PATCH 17/19] upgraded MatProInterface --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index a602e97..194d383 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.0 toolchain go1.23.9 require ( - github.com/MatProGo-dev/MatProInterface.go v0.6.4 - github.com/MatProGo-dev/SymbolicMath.go v0.2.6 + github.com/MatProGo-dev/MatProInterface.go v0.6.5-1 + github.com/MatProGo-dev/SymbolicMath.go v0.3.2-0.20251017032605-a7dee10c22bf gonum.org/v1/gonum v0.16.0 ) diff --git a/go.sum b/go.sum index 7e87577..2c52a4f 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ -github.com/MatProGo-dev/MatProInterface.go v0.6.4 h1:tjoDJMmAelPVXz7gZcdUJyLYpSd2Xb9Pbqlb5FOQmTc= -github.com/MatProGo-dev/MatProInterface.go v0.6.4/go.mod h1:v7e1RkEpIX5F2l/AeDy04CCaVERBA7vGI8rjVItB3dc= -github.com/MatProGo-dev/SymbolicMath.go v0.2.6 h1:0THkOKIjdjadIb9MHIUflk08U7tv17KvtQPOP3eMOfk= -github.com/MatProGo-dev/SymbolicMath.go v0.2.6/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU= +github.com/MatProGo-dev/MatProInterface.go v0.6.5-1 h1:dOpwi8mQiHSkA2oXY1B2v/uOM/3ZvZSwbmMomsMLakY= +github.com/MatProGo-dev/MatProInterface.go v0.6.5-1/go.mod h1:Ip6cN6/uT39LSc6XCqIPnwXLq9N+T/4nLtDPPmHYwhA= +github.com/MatProGo-dev/SymbolicMath.go v0.3.2-0.20251017032605-a7dee10c22bf h1:fvHlqO39XHb/TfMm979zsnrcvZDSAFU7PW61g1UQCW8= +github.com/MatProGo-dev/SymbolicMath.go v0.3.2-0.20251017032605-a7dee10c22bf/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= From 5919a5edb74f5659f16c0c36533b6117976555fe Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Fri, 17 Oct 2025 00:18:48 -0400 Subject: [PATCH 18/19] With the introduction of improved termination detection + better exiting variable selection, it looks like we've come up with a better solution --- algorithms/tableau/errors.go | 18 +++++ algorithms/tableau/selection/blands_rule.go | 5 +- algorithms/tableau/state.go | 2 +- examples/box2/box.go | 83 +++++++++++++++++++++ utils/tableau.go | 22 ++++++ 5 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 algorithms/tableau/errors.go create mode 100644 examples/box2/box.go diff --git a/algorithms/tableau/errors.go b/algorithms/tableau/errors.go new file mode 100644 index 0000000..ff38335 --- /dev/null +++ b/algorithms/tableau/errors.go @@ -0,0 +1,18 @@ +package tableau_algorithm1 + +type VariableSelectionError struct { + EnteringVarIndex int + ExitingVarIndex int +} + +func (e VariableSelectionError) Error() string { + if e.ExitingVarIndex == -1 { + return "VariableSelectionError: No exiting variable found, problem can not be improved." + } + + if e.EnteringVarIndex == -1 { + return "VariableSelectionError: No entering variable found, current solution is optimal." + } + + return "VariableSelectionError: Unknown variable selection error." +} diff --git a/algorithms/tableau/selection/blands_rule.go b/algorithms/tableau/selection/blands_rule.go index 0aaa3cc..f0e4670 100644 --- a/algorithms/tableau/selection/blands_rule.go +++ b/algorithms/tableau/selection/blands_rule.go @@ -2,6 +2,7 @@ package selection import ( "fmt" + "math" "github.com/MatProGo-dev/SymbolicMath.go/symbolic" "github.com/MatProGo-dev/simplex/utils" @@ -65,7 +66,7 @@ func (br BlandsRule) SelectExitingVariable(tableau utils.Tableau, enteringVarIdx // Create the vector of ratios ratios := make([]float64, tableau.NumberOfConstraints()) for i := 0; i < tableau.NumberOfConstraints(); i++ { - if A.At(i, enteringVarIdx) > 0 { + if math.Abs(A.At(i, enteringVarIdx)) > 1e-12 { ratios[i] = b.AtVec(i) / A.At(i, enteringVarIdx) } else { ratios[i] = -1.0 // Indicate that this variable cannot be used @@ -104,7 +105,7 @@ func (br BlandsRule) SelectEnteringAndExitingVariables(tableau utils.Tableau) (i // Select the exiting variable exitingVarIdx := br.SelectExitingVariable(tableau, enteringVarIdx) if exitingVarIdx == -1 { - return enteringVarIdx, -1, fmt.Errorf("BlandsRule: No exiting variable found, problem is unbounded (?)") + return enteringVarIdx, -1, fmt.Errorf("BlandsRule: No exiting variable found, problem can not be improved.") } return enteringVarIdx, exitingVarIdx, nil diff --git a/algorithms/tableau/state.go b/algorithms/tableau/state.go index fe9a0e5..dde90f7 100644 --- a/algorithms/tableau/state.go +++ b/algorithms/tableau/state.go @@ -250,7 +250,7 @@ func (state *TableauAlgorithmState) CalculateNextState() (TableauAlgorithmState, selectionRule := selection.BlandsRule{} enteringVarIdx, exitingVarIdx, err := selectionRule.SelectEnteringAndExitingVariables(*state.Tableau) if err != nil { - return TableauAlgorithmState{}, fmt.Errorf("TableauAlgorithmState: Failed to select entering and exiting variables (%v)", err) + return TableauAlgorithmState{}, VariableSelectionError{EnteringVarIndex: enteringVarIdx, ExitingVarIndex: exitingVarIdx} } // fmt.Println("Entering variable index: ", enteringVarIdx, " (", state.Tableau.Variables[enteringVarIdx], ")") diff --git a/examples/box2/box.go b/examples/box2/box.go new file mode 100644 index 0000000..6ddd8e8 --- /dev/null +++ b/examples/box2/box.go @@ -0,0 +1,83 @@ +package main + +import ( + "github.com/MatProGo-dev/MatProInterface.go/problem" + getKVector "github.com/MatProGo-dev/SymbolicMath.go/get/KVector" + "github.com/MatProGo-dev/SymbolicMath.go/symbolic" + "github.com/MatProGo-dev/simplex/simplexSolver" + "gonum.org/v1/gonum/mat" +) + +/* +Description: + + This function builds an optimization problem where we attempt to find + the optimal solution to a linear programming problem that is in a feasible + region that is a box. + + The problem will be: + + Minimize: x1 - 2*x2 + Subject to: + -1 <= x1 <= 1 + -1 <= x2 <= 1 + + The optimal solution is x1 = -1, x2 = 1 with an objective value of -3. +*/ +func BuildOptimizationProblem() problem.OptimizationProblem { + // setup + varCount := 2 + out := problem.NewProblem("Box LP Problem") + + // Create the variables + x := out.AddVariableVector(varCount) + + // Create the objective + c := getKVector.From( + []float64{1, -2}, + ) + out.SetObjective( + c.Transpose().Multiply(x), + problem.SenseMinimize, + ) + + // Create the constraints + // - x >= -1 + out.Constraints = append( + out.Constraints, + x.GreaterEq(mat.NewVecDense(varCount, []float64{-1, -1})), + ) + + // - x <= 1 + out.Constraints = append( + out.Constraints, + x.LessEq(symbolic.OnesVector(varCount)), + ) + + return *out +} + +func main() { + // This is just a placeholder to make the package "main" valid. + trickyProblem := BuildOptimizationProblem() + + // Use solver to solve the problem + solver := simplexSolver.New("Simplex Solver Example") + solver.IterationLimit = 100 + + // Solve the problem + solution, err := solver.Solve(trickyProblem) + if err != nil { + panic(err) + } + + // Print the solution + solutionMessage, _ := solution.Status.ToMessage() + println("Solution Status: ", solutionMessage) + println("Objective Value: ", solution.Objective) + println("Number of Iterations: ", solution.Iterations) + println("Variable Values: ") + for varName, varValue := range solution.VariableValues { + println(" ", varName, ": ", varValue) + } +} diff --git a/utils/tableau.go b/utils/tableau.go index b3188ea..3ae4fb1 100644 --- a/utils/tableau.go +++ b/utils/tableau.go @@ -457,6 +457,28 @@ func (tableau *Tableau) CanNotBeImproved() bool { } } + // For each coefficient that is negative, check if there is a corresponding + // row in the Tableau matrix that has a positive ratio (i.e., b[i] / A[i, enteringVarIdx] > 0). + // If there is no such row for any entering variable, then the problem can not be improved. + A := tableau.A() + nRowsA, _ := A.Dims() + b := tableau.B() + for enteringVarIdx := 0; enteringVarIdx < c.Len(); enteringVarIdx++ { + if c.AtVec(enteringVarIdx) < 0 { + // Check for positive ratios + hasPositiveRatio := false + for rowIdx := 0; rowIdx < nRowsA; rowIdx++ { + if b.AtVec(rowIdx)/A.At(rowIdx, enteringVarIdx) > 0 { + hasPositiveRatio = true + break + } + } + if hasPositiveRatio { + return false + } + } + } + return true } From 05e617923ec61c2d5a9dabf3bb174d60611af1bf Mon Sep 17 00:00:00 2001 From: Kwesi Rutledge Date: Fri, 17 Oct 2025 00:29:40 -0400 Subject: [PATCH 19/19] Fixed issues with the unused exported member Objective in SimplexSolution --- algorithms/stanford/stanford.go | 6 ++---- algorithms/tableau/state.go | 11 ----------- examples/box1/box.go | 17 ++++++++++++----- examples/box2/box.go | 15 ++++++++++----- examples/gonum_bug1/try_bug.go | 15 ++++++++++----- .../the_simplex_method_part_ii.go | 12 +++++++----- solution/simplex_solution.go | 10 +++++++--- 7 files changed, 48 insertions(+), 38 deletions(-) diff --git a/algorithms/stanford/stanford.go b/algorithms/stanford/stanford.go index 089192f..984cd5d 100644 --- a/algorithms/stanford/stanford.go +++ b/algorithms/stanford/stanford.go @@ -194,11 +194,10 @@ func (algo *StanfordAlgorithm) ComputeSolutionFromState(state StanfordAlgorithmS } // Compute the value of the objective function - objValue, err := algo.ComputeObjectiveFunctionValueWithFeasibleBasicSolution(state, xBasic) + _, err = algo.ComputeObjectiveFunctionValueWithFeasibleBasicSolution(state, xBasic) if err != nil { return solution, fmt.Errorf("StanfordAlgorithm: Failed to compute objective function value (%v)", err) } - solution.Objective = objValue // Set the values of the basic variables for ii, bv := range state.BasicVariables { @@ -293,8 +292,7 @@ func (algo *StanfordAlgorithm) Solve(initialState StanfordAlgorithmState) (simpl if iter == algo.IterationLimit { return simplex_solution.SimplexSolution{ - Objective: objII, - Status: solution_status.ITERATION_LIMIT, + Status: solution_status.ITERATION_LIMIT, }, nil } diff --git a/algorithms/tableau/state.go b/algorithms/tableau/state.go index dde90f7..ae187ab 100644 --- a/algorithms/tableau/state.go +++ b/algorithms/tableau/state.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/MatProGo-dev/MatProInterface.go/problem" - "github.com/MatProGo-dev/MatProInterface.go/solution" "github.com/MatProGo-dev/SymbolicMath.go/symbolic" "github.com/MatProGo-dev/simplex/algorithms" "github.com/MatProGo-dev/simplex/algorithms/tableau/selection" @@ -377,16 +376,6 @@ func (state *TableauAlgorithmState) ToSolution( ) } - // Construct Objective Value - sol.Objective, err = solution.GetOptimalObjectiveValue(&sol) - if err != nil { - return sol, - fmt.Errorf( - "There was an issue getting the objective value at termination: %v", - err, - ) - } - // Assemble Solution Output return sol, nil } diff --git a/examples/box1/box.go b/examples/box1/box.go index 9780d98..ba50c25 100644 --- a/examples/box1/box.go +++ b/examples/box1/box.go @@ -2,6 +2,7 @@ package main import ( "github.com/MatProGo-dev/MatProInterface.go/problem" + "github.com/MatProGo-dev/MatProInterface.go/solution" getKVector "github.com/MatProGo-dev/SymbolicMath.go/get/KVector" "github.com/MatProGo-dev/SymbolicMath.go/symbolic" "github.com/MatProGo-dev/simplex/simplexSolver" @@ -65,18 +66,24 @@ func main() { solver.IterationLimit = 100 // Solve the problem - solution, err := solver.Solve(trickyProblem) + sol, err := solver.Solve(trickyProblem) if err != nil { panic(err) } // Print the solution - solutionMessage, _ := solution.Status.ToMessage() + solutionMessage, _ := sol.Status.ToMessage() println("Solution Status: ", solutionMessage) - println("Objective Value: ", solution.Objective) - println("Number of Iterations: ", solution.Iterations) + + optObj, err := solution.GetOptimalObjectiveValue(&sol) + if err != nil { + panic(err) + } + println("Objective Value: ", optObj) + + println("Number of Iterations: ", sol.Iterations) println("Variable Values: ") - for varName, varValue := range solution.VariableValues { + for varName, varValue := range sol.VariableValues { println(" ", varName, ": ", varValue) } } diff --git a/examples/box2/box.go b/examples/box2/box.go index 6ddd8e8..efb14ff 100644 --- a/examples/box2/box.go +++ b/examples/box2/box.go @@ -2,6 +2,7 @@ package main import ( "github.com/MatProGo-dev/MatProInterface.go/problem" + "github.com/MatProGo-dev/MatProInterface.go/solution" getKVector "github.com/MatProGo-dev/SymbolicMath.go/get/KVector" "github.com/MatProGo-dev/SymbolicMath.go/symbolic" "github.com/MatProGo-dev/simplex/simplexSolver" @@ -66,18 +67,22 @@ func main() { solver.IterationLimit = 100 // Solve the problem - solution, err := solver.Solve(trickyProblem) + sol, err := solver.Solve(trickyProblem) if err != nil { panic(err) } // Print the solution - solutionMessage, _ := solution.Status.ToMessage() + solutionMessage, _ := sol.Status.ToMessage() println("Solution Status: ", solutionMessage) - println("Objective Value: ", solution.Objective) - println("Number of Iterations: ", solution.Iterations) + optObj, err := solution.GetOptimalObjectiveValue(&sol) + if err != nil { + panic(err) + } + println("Objective Value: ", optObj) + println("Number of Iterations: ", sol.Iterations) println("Variable Values: ") - for varName, varValue := range solution.VariableValues { + for varName, varValue := range sol.VariableValues { println(" ", varName, ": ", varValue) } } diff --git a/examples/gonum_bug1/try_bug.go b/examples/gonum_bug1/try_bug.go index 6545d10..a16bd6d 100644 --- a/examples/gonum_bug1/try_bug.go +++ b/examples/gonum_bug1/try_bug.go @@ -2,6 +2,7 @@ package main import ( "github.com/MatProGo-dev/MatProInterface.go/problem" + "github.com/MatProGo-dev/MatProInterface.go/solution" getKMatrix "github.com/MatProGo-dev/SymbolicMath.go/get/KMatrix" getKVector "github.com/MatProGo-dev/SymbolicMath.go/get/KVector" "github.com/MatProGo-dev/simplex/simplexSolver" @@ -76,18 +77,22 @@ func main() { solver.IterationLimit = 100 // Solve the problem - solution, err := solver.Solve(trickyProblem) + sol, err := solver.Solve(trickyProblem) if err != nil { panic(err) } // Print the solution - solutionMessage, _ := solution.Status.ToMessage() + solutionMessage, _ := sol.Status.ToMessage() println("Solution Status: ", solutionMessage) - println("Objective Value: ", solution.Objective) - println("Number of Iterations: ", solution.Iterations) + optObj, err := solution.GetOptimalObjectiveValue(&sol) + if err != nil { + panic(err) + } + println("Objective Value: ", optObj) + println("Number of Iterations: ", sol.Iterations) println("Variable Values: ") - for varName, varValue := range solution.VariableValues { + for varName, varValue := range sol.VariableValues { println(" ", varName, ": ", varValue) } } diff --git a/examples/sergiy_butenko1/the_simplex_method_part_ii.go b/examples/sergiy_butenko1/the_simplex_method_part_ii.go index d9eed9d..6d8a9eb 100644 --- a/examples/sergiy_butenko1/the_simplex_method_part_ii.go +++ b/examples/sergiy_butenko1/the_simplex_method_part_ii.go @@ -1,6 +1,7 @@ package main import ( + "github.com/MatProGo-dev/MatProInterface.go/solution" "github.com/MatProGo-dev/simplex/simplexSolver" "github.com/MatProGo-dev/simplex/utils/examples" ) @@ -17,18 +18,19 @@ func main() { solver.IterationLimit = 100 // Solve the problem - solution, err := solver.Solve(*problem5) + sol, err := solver.Solve(*problem5) if err != nil { panic(err) } // Print the solution - solutionMessage, _ := solution.Status.ToMessage() + solutionMessage, _ := sol.Status.ToMessage() println("Solution Status: ", solutionMessage) - println("Objective Value: ", solution.Objective) - println("Number of Iterations: ", solution.Iterations) + optVal, _ := solution.GetOptimalObjectiveValue(&sol) + println("Objective Value: ", optVal) + println("Number of Iterations: ", sol.Iterations) println("Variable Values: ") - for varName, varValue := range solution.VariableValues { + for varName, varValue := range sol.VariableValues { println(" ", varName, ": ", varValue) } } diff --git a/solution/simplex_solution.go b/solution/simplex_solution.go index 403b5d6..def27e0 100644 --- a/solution/simplex_solution.go +++ b/solution/simplex_solution.go @@ -2,6 +2,7 @@ package simplex_solution import ( "github.com/MatProGo-dev/MatProInterface.go/problem" + "github.com/MatProGo-dev/MatProInterface.go/solution" solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" ) @@ -11,8 +12,6 @@ type SimplexSolution struct { // VariableValues maps variable IDs (as uint64) to their solution values. // The uint64 key typically represents the unique identifier or index of a variable in the model. VariableValues map[uint64]float64 - // Objective is the value of the objective function at the solution. - Objective float64 // Status indicates the status of the solution (e.g., optimal, infeasible). Status solution_status.SolutionStatus Iterations int @@ -26,7 +25,12 @@ func (sol *SimplexSolution) GetValueMap() map[uint64]float64 { } func (sol *SimplexSolution) GetOptimalValue() float64 { - return sol.Objective + // Use the symbolic.Solution interface to compute the optimal value + optVal, err := solution.GetOptimalObjectiveValue(sol) + if err != nil { + return 0.0 + } + return optVal } func (sol *SimplexSolution) GetStatus() solution_status.SolutionStatus {