From cbe11e9202265bfb82ce4f92352d3a6cd354eb25 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 01:48:32 +0000 Subject: [PATCH 1/4] Initial plan From daed746197512612b7138de5a867d923293cfbb4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 01:54:24 +0000 Subject: [PATCH 2/4] Add comprehensive tests for SimplexSolution Co-authored-by: kwesiRutledge <9002730+kwesiRutledge@users.noreply.github.com> --- testing/solution/simplex_solution_test.go | 286 ++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 testing/solution/simplex_solution_test.go diff --git a/testing/solution/simplex_solution_test.go b/testing/solution/simplex_solution_test.go new file mode 100644 index 0000000..17973aa --- /dev/null +++ b/testing/solution/simplex_solution_test.go @@ -0,0 +1,286 @@ +package solution_test + +import ( + "testing" + + "github.com/MatProGo-dev/MatProInterface.go/problem" + solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" + simplex_solution "github.com/MatProGo-dev/simplex/solution" +) + +/* +TestSimplexSolution_GetValueMap1 +Description: + + Tests that the GetValueMap() method returns the correct variable values map. +*/ +func TestSimplexSolution_GetValueMap1(t *testing.T) { + // Setup + variableValues := map[uint64]float64{ + 0: 1.0, + 1: 2.0, + 2: 3.0, + } + + sol := simplex_solution.SimplexSolution{ + VariableValues: variableValues, + Objective: 10.0, + Status: solution_status.OPTIMAL, + Iterations: 5, + } + + // Test + result := sol.GetValueMap() + + // Verify + if len(result) != len(variableValues) { + t.Errorf("Expected %d values, but got %d", len(variableValues), len(result)) + } + + for key, expectedValue := range variableValues { + if result[key] != expectedValue { + t.Errorf("Expected value %v for variable %d, but got %v", expectedValue, key, result[key]) + } + } +} + +/* +TestSimplexSolution_GetOptimalValue1 +Description: + + Tests that the GetOptimalValue() method returns the correct objective value. +*/ +func TestSimplexSolution_GetOptimalValue1(t *testing.T) { + // Setup + expectedObjective := 42.5 + + sol := simplex_solution.SimplexSolution{ + VariableValues: map[uint64]float64{0: 1.0}, + Objective: expectedObjective, + Status: solution_status.OPTIMAL, + Iterations: 3, + } + + // Test + result := sol.GetOptimalValue() + + // Verify + if result != expectedObjective { + t.Errorf("Expected objective value %v, but got %v", expectedObjective, result) + } +} + +/* +TestSimplexSolution_GetStatus1 +Description: + + Tests that the GetStatus() method returns the correct solution status + for an optimal solution. +*/ +func TestSimplexSolution_GetStatus1(t *testing.T) { + // Setup + sol := simplex_solution.SimplexSolution{ + VariableValues: map[uint64]float64{0: 1.0}, + Objective: 10.0, + Status: solution_status.OPTIMAL, + Iterations: 2, + } + + // Test + result := sol.GetStatus() + + // Verify + if result != solution_status.OPTIMAL { + t.Errorf("Expected status %v, but got %v", solution_status.OPTIMAL, result) + } +} + +/* +TestSimplexSolution_GetStatus2 +Description: + + Tests that the GetStatus() method returns the correct solution status + for an infeasible solution. +*/ +func TestSimplexSolution_GetStatus2(t *testing.T) { + // Setup + sol := simplex_solution.SimplexSolution{ + VariableValues: map[uint64]float64{}, + Objective: 0.0, + Status: solution_status.INFEASIBLE, + Iterations: 1, + } + + // Test + result := sol.GetStatus() + + // Verify + if result != solution_status.INFEASIBLE { + t.Errorf("Expected status %v, but got %v", solution_status.INFEASIBLE, result) + } +} + +/* +TestSimplexSolution_GetStatus3 +Description: + + Tests that the GetStatus() method returns the correct solution status + for an unbounded solution. +*/ +func TestSimplexSolution_GetStatus3(t *testing.T) { + // Setup + sol := simplex_solution.SimplexSolution{ + VariableValues: map[uint64]float64{}, + Objective: 0.0, + Status: solution_status.UNBOUNDED, + Iterations: 0, + } + + // Test + result := sol.GetStatus() + + // Verify + if result != solution_status.UNBOUNDED { + t.Errorf("Expected status %v, but got %v", solution_status.UNBOUNDED, result) + } +} + +/* +TestSimplexSolution_GetProblem1 +Description: + + Tests that the GetProblem() method returns the correct original problem. +*/ +func TestSimplexSolution_GetProblem1(t *testing.T) { + // Setup + originalProblem := problem.NewProblem("TestProblem") + originalProblem.AddVariableVector(2) + + sol := simplex_solution.SimplexSolution{ + VariableValues: map[uint64]float64{0: 1.0, 1: 2.0}, + Objective: 10.0, + Status: solution_status.OPTIMAL, + Iterations: 4, + OriginalProblem: originalProblem, + } + + // Test + result := sol.GetProblem() + + // Verify + if result == nil { + t.Errorf("Expected a non-nil problem, but got nil") + } + + if result != originalProblem { + t.Errorf("Expected the same problem reference, but got a different one") + } + + if result.Name != "TestProblem" { + t.Errorf("Expected problem name 'TestProblem', but got '%s'", result.Name) + } +} + +/* +TestSimplexSolution_GetProblem2 +Description: + + Tests that the GetProblem() method returns nil when no problem is attached. +*/ +func TestSimplexSolution_GetProblem2(t *testing.T) { + // Setup + sol := simplex_solution.SimplexSolution{ + VariableValues: map[uint64]float64{0: 1.0}, + Objective: 5.0, + Status: solution_status.OPTIMAL, + Iterations: 2, + OriginalProblem: nil, + } + + // Test + result := sol.GetProblem() + + // Verify + if result != nil { + t.Errorf("Expected nil problem, but got %v", result) + } +} + +/* +TestSimplexSolution_EmptyVariableValues +Description: + + Tests that the SimplexSolution can handle an empty variable values map. +*/ +func TestSimplexSolution_EmptyVariableValues(t *testing.T) { + // Setup + sol := simplex_solution.SimplexSolution{ + VariableValues: map[uint64]float64{}, + Objective: 0.0, + Status: solution_status.INFEASIBLE, + Iterations: 0, + } + + // Test + result := sol.GetValueMap() + + // Verify + if result == nil { + t.Errorf("Expected non-nil map, but got nil") + } + + if len(result) != 0 { + t.Errorf("Expected empty map, but got %d values", len(result)) + } +} + +/* +TestSimplexSolution_CompleteStructure +Description: + + Tests a complete SimplexSolution with all fields populated. +*/ +func TestSimplexSolution_CompleteStructure(t *testing.T) { + // Setup + variableValues := map[uint64]float64{ + 0: 125.0, + 1: 300.0, + 2: 25.0, + } + objective := 9875.0 + iterations := 10 + + originalProblem := problem.NewProblem("CompleteProblem") + originalProblem.AddVariableVector(3) + + sol := simplex_solution.SimplexSolution{ + VariableValues: variableValues, + Objective: objective, + Status: solution_status.OPTIMAL, + Iterations: iterations, + OriginalProblem: originalProblem, + } + + // Test all methods + if sol.GetOptimalValue() != objective { + t.Errorf("Expected objective %v, but got %v", objective, sol.GetOptimalValue()) + } + + if sol.GetStatus() != solution_status.OPTIMAL { + t.Errorf("Expected status OPTIMAL, but got %v", sol.GetStatus()) + } + + valueMap := sol.GetValueMap() + if len(valueMap) != len(variableValues) { + t.Errorf("Expected %d variables, but got %d", len(variableValues), len(valueMap)) + } + + prob := sol.GetProblem() + if prob == nil || prob.Name != "CompleteProblem" { + t.Errorf("Expected problem 'CompleteProblem', but got %v", prob) + } + + if sol.Iterations != iterations { + t.Errorf("Expected %d iterations, but got %d", iterations, sol.Iterations) + } +} From f45892e14eb945e8c98d9d9100c6181b667b4a63 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 01:57:10 +0000 Subject: [PATCH 3/4] Add comprehensive tests for TableauAlgorithmState Co-authored-by: kwesiRutledge <9002730+kwesiRutledge@users.noreply.github.com> --- testing/algorithms/tableau/state_test.go | 484 +++++++++++++++++++++++ 1 file changed, 484 insertions(+) diff --git a/testing/algorithms/tableau/state_test.go b/testing/algorithms/tableau/state_test.go index 4d8c7a7..002e22f 100644 --- a/testing/algorithms/tableau/state_test.go +++ b/testing/algorithms/tableau/state_test.go @@ -3,7 +3,9 @@ package tableau import ( "testing" + solution_status "github.com/MatProGo-dev/MatProInterface.go/solution/status" tableau_algorithm1 "github.com/MatProGo-dev/simplex/algorithms/tableau" + tableau_termination "github.com/MatProGo-dev/simplex/algorithms/tableau/termination" "github.com/MatProGo-dev/simplex/utils" "github.com/MatProGo-dev/simplex/utils/examples" ) @@ -67,3 +69,485 @@ func TestTableau_CalculateOptimalSolution1(t *testing.T) { } } } + +/* +TestTableauAlgorithmState_Check1 +Description: + + Tests that the Check() method returns no error for a valid state. +*/ +func TestTableauAlgorithmState_Check1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Test + err = state.Check() + + // Verify + if err != nil { + t.Errorf("Expected no error for valid state, but got: %v", err) + } +} + +/* +TestTableauAlgorithmState_Check2 +Description: + + Tests that the Check() method returns an error when IterationCount is negative. +*/ +func TestTableauAlgorithmState_Check2(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: -5, + } + + // Test + err = state.Check() + + // Verify + if err == nil { + t.Errorf("Expected an error for negative iteration count, but got none") + } +} + +/* +TestTableauAlgorithmState_CheckTerminationCondition1 +Description: + + Tests that CheckTerminationCondition() returns false for initial state + (not yet optimal). +*/ +func TestTableauAlgorithmState_CheckTerminationCondition1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Test + terminated, err := state.CheckTerminationCondition() + + // Verify + if err != nil { + t.Errorf("Expected no error, but got: %v", err) + } + + if terminated { + t.Errorf("Expected state to not be terminated initially, but it was") + } +} + +/* +TestTableauAlgorithmState_CheckTerminationCondition2 +Description: + + Tests that CheckTerminationCondition() returns true for an optimal state. +*/ +func TestTableauAlgorithmState_CheckTerminationCondition2(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state0 := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Move to optimal state + state1, err := state0.CalculateNextState() + if err != nil { + t.Errorf("there was an issue calculating the next state: %v", err) + } + state2, err := state1.CalculateNextState() + if err != nil { + t.Errorf("there was an issue calculating the next state: %v", err) + } + + // Test + terminated, err := state2.CheckTerminationCondition() + + // Verify + if err != nil { + t.Errorf("Expected no error, but got: %v", err) + } + + if !terminated { + t.Errorf("Expected state to be terminated at optimal, but it wasn't") + } +} + +/* +TestTableauAlgorithmState_GetBasicVariables1 +Description: + + Tests that GetBasicVariables() returns the correct basic variables. +*/ +func TestTableauAlgorithmState_GetBasicVariables1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Test + basicVars := state.GetBasicVariables() + + // Verify + if len(basicVars) == 0 { + t.Errorf("Expected non-empty basic variables, but got empty slice") + } + + // For the initial tableau, we should have slack variables as basic variables + // (4 constraints = 4 slack variables) + if len(basicVars) != 4 { + t.Errorf("Expected 4 basic variables, but got %d", len(basicVars)) + } +} + +/* +TestTableauAlgorithmState_GetNonBasicVariables1 +Description: + + Tests that GetNonBasicVariables() returns the correct non-basic variables. +*/ +func TestTableauAlgorithmState_GetNonBasicVariables1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Test + nonBasicVars := state.GetNonBasicVariables() + + // Verify + if len(nonBasicVars) == 0 { + t.Errorf("Expected non-empty non-basic variables, but got empty slice") + } + + // For the initial tableau, we should have original variables as non-basic + // (2 original variables) + if len(nonBasicVars) != 2 { + t.Errorf("Expected 2 non-basic variables, but got %d", len(nonBasicVars)) + } +} + +/* +TestTableauAlgorithmState_NumberOfIterations1 +Description: + + Tests that NumberOfIterations() returns the correct iteration count. +*/ +func TestTableauAlgorithmState_NumberOfIterations1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 7, + } + + // Test + iterations := state.NumberOfIterations() + + // Verify + if iterations != 7 { + t.Errorf("Expected 7 iterations, but got %d", iterations) + } +} + +/* +TestTableauAlgorithmState_NumberOfVariables1 +Description: + + Tests that NumberOfVariables() returns the correct total variable count. +*/ +func TestTableauAlgorithmState_NumberOfVariables1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Test + numVars := state.NumberOfVariables() + + // Verify + // 2 original variables + 4 slack variables = 6 total + if numVars != 6 { + t.Errorf("Expected 6 variables, but got %d", numVars) + } +} + +/* +TestTableauAlgorithmState_NumberOfConstraints1 +Description: + + Tests that NumberOfConstraints() returns the correct constraint count. +*/ +func TestTableauAlgorithmState_NumberOfConstraints1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Test + numConstraints := state.NumberOfConstraints() + + // Verify + // Test problem 5 has 4 constraints + if numConstraints != 4 { + t.Errorf("Expected 4 constraints, but got %d", numConstraints) + } +} + +/* +TestTableauAlgorithmState_GetReducedCostVector1 +Description: + + Tests that GetReducedCostVector() returns a vector without errors. +*/ +func TestTableauAlgorithmState_GetReducedCostVector1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Test + reducedCost, err := state.GetReducedCostVector() + + // Verify + if err != nil { + t.Errorf("Expected no error, but got: %v", err) + } + + if reducedCost == nil { + t.Errorf("Expected non-nil reduced cost vector") + } + + // The reduced cost vector should have length equal to number of variables + if reducedCost.Len() != state.NumberOfVariables() { + t.Errorf("Expected reduced cost vector length %d, but got %d", + state.NumberOfVariables(), reducedCost.Len()) + } +} + +/* +TestTableauAlgorithmState_GetShadowPrice1 +Description: + + Tests that GetShadowPrice() returns a vector without errors. +*/ +func TestTableauAlgorithmState_GetShadowPrice1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, _, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Test + shadowPrice, err := state.GetShadowPrice() + + // Verify + if err != nil { + t.Errorf("Expected no error, but got: %v", err) + } + + if shadowPrice == nil { + t.Errorf("Expected non-nil shadow price vector") + } + + // The shadow price vector should have length equal to number of variables + if shadowPrice.Len() != state.NumberOfVariables() { + t.Errorf("Expected shadow price vector length %d, but got %d", + state.NumberOfVariables(), shadowPrice.Len()) + } +} + +/* +TestTableauAlgorithmState_CreateOptimalValuesMap1 +Description: + + Tests that CreateOptimalValuesMap() creates a proper values map. +*/ +func TestTableauAlgorithmState_CreateOptimalValuesMap1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, varMap, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state0 := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Move to optimal state + state1, err := state0.CalculateNextState() + if err != nil { + t.Errorf("there was an issue calculating the next state: %v", err) + } + state2, err := state1.CalculateNextState() + if err != nil { + t.Errorf("there was an issue calculating the next state: %v", err) + } + + // Test + valuesMap, err := state2.CreateOptimalValuesMap(varMap) + + // Verify + if err != nil { + t.Errorf("Expected no error, but got: %v", err) + } + + if valuesMap == nil { + t.Errorf("Expected non-nil values map") + } + + // Should have values for the original variables + if len(valuesMap) == 0 { + t.Errorf("Expected non-empty values map") + } + + // Check expected values for TestProblem5 + // x1 = 125, x2 = 300 + for varID, value := range valuesMap { + if varID == 0 && value != 125.0 { + t.Errorf("Expected x1 = 125.0, but got %v", value) + } + if varID == 1 && value != 300.0 { + t.Errorf("Expected x2 = 300.0, but got %v", value) + } + } +} + +/* +TestTableauAlgorithmState_ToSolution1 +Description: + + Tests that ToSolution() creates a valid SimplexSolution. +*/ +func TestTableauAlgorithmState_ToSolution1(t *testing.T) { + // Setup + testProblem := examples.GetTestProblem5() + initialTableau, varMap, err := utils.GetInitialTableauFrom(testProblem) + if err != nil { + t.Errorf("there was an issue creating the initial tableau: %v", err) + } + + state0 := tableau_algorithm1.TableauAlgorithmState{ + Tableau: &initialTableau, + IterationCount: 0, + } + + // Move to optimal state + state1, err := state0.CalculateNextState() + if err != nil { + t.Errorf("there was an issue calculating the next state: %v", err) + } + state2, err := state1.CalculateNextState() + if err != nil { + t.Errorf("there was an issue calculating the next state: %v", err) + } + + // Test + solution, err := state2.ToSolution( + tableau_termination.OptimalSolutionFound, + varMap, + testProblem, + ) + + // Verify + if err != nil { + t.Errorf("Expected no error, but got: %v", err) + } + + // Check solution status + if solution.GetStatus() != solution_status.OPTIMAL { + t.Errorf("Expected OPTIMAL status, but got %v", solution.GetStatus()) + } + + // Check iteration count + if solution.Iterations != 2 { + t.Errorf("Expected 2 iterations, but got %d", solution.Iterations) + } + + // Check that we have variable values + if len(solution.VariableValues) == 0 { + t.Errorf("Expected non-empty variable values") + } + + // Check that problem is attached + if solution.GetProblem() == nil { + t.Errorf("Expected non-nil problem") + } +} + From da52fb79161604406921b278e903c45e39e775f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 02:00:04 +0000 Subject: [PATCH 4/4] Address code review feedback - fix multi-line error message formatting Co-authored-by: kwesiRutledge <9002730+kwesiRutledge@users.noreply.github.com> --- testing/algorithms/tableau/state_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/testing/algorithms/tableau/state_test.go b/testing/algorithms/tableau/state_test.go index 002e22f..ca37c93 100644 --- a/testing/algorithms/tableau/state_test.go +++ b/testing/algorithms/tableau/state_test.go @@ -388,8 +388,7 @@ func TestTableauAlgorithmState_GetReducedCostVector1(t *testing.T) { // The reduced cost vector should have length equal to number of variables if reducedCost.Len() != state.NumberOfVariables() { - t.Errorf("Expected reduced cost vector length %d, but got %d", - state.NumberOfVariables(), reducedCost.Len()) + t.Errorf("Expected reduced cost vector length %d, but got %d", state.NumberOfVariables(), reducedCost.Len()) } } @@ -426,8 +425,7 @@ func TestTableauAlgorithmState_GetShadowPrice1(t *testing.T) { // The shadow price vector should have length equal to number of variables if shadowPrice.Len() != state.NumberOfVariables() { - t.Errorf("Expected shadow price vector length %d, but got %d", - state.NumberOfVariables(), shadowPrice.Len()) + t.Errorf("Expected shadow price vector length %d, but got %d", state.NumberOfVariables(), shadowPrice.Len()) } }