Skip to content

Commit f8bd25a

Browse files
Add FindValueOfExpression function to solution package
Co-authored-by: kwesiRutledge <[email protected]>
1 parent 8a16f3f commit f8bd25a

File tree

2 files changed

+219
-0
lines changed

2 files changed

+219
-0
lines changed

solution/solution.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,39 @@ func ExtractValueOfVariable(s Solution, v symbolic.Variable) (float64, error) {
3737
idx := v.ID // Extract index of v
3838
return ExtractValueOfVariableWithID(s, idx)
3939
}
40+
41+
// FindValueOfExpression evaluates a symbolic expression using the values from a solution.
42+
// It substitutes all variables in the expression with their values from the solution
43+
// and returns the resulting scalar value.
44+
func FindValueOfExpression(s Solution, expr symbolic.Expression) (float64, error) {
45+
// Get all variables in the expression
46+
vars := expr.Variables()
47+
48+
// Create a substitution map from variables to their constant values
49+
subMap := make(map[symbolic.Variable]symbolic.Expression)
50+
for _, v := range vars {
51+
val, err := ExtractValueOfVariable(s, v)
52+
if err != nil {
53+
return 0.0, fmt.Errorf(
54+
"failed to extract value for variable %v: %w",
55+
v.ID,
56+
err,
57+
)
58+
}
59+
subMap[v] = symbolic.K(val)
60+
}
61+
62+
// Substitute all variables with their values
63+
resultExpr := expr.SubstituteAccordingTo(subMap)
64+
65+
// Type assert to K (constant) to extract the float64 value
66+
resultK, ok := resultExpr.(symbolic.K)
67+
if !ok {
68+
return 0.0, fmt.Errorf(
69+
"expected substituted expression to be a constant, got type %T",
70+
resultExpr,
71+
)
72+
}
73+
74+
return float64(resultK), nil
75+
}

testing/solution/solution_test.go

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,186 @@ func TestSolution_Value1(t *testing.T) {
134134
}
135135

136136
}
137+
138+
/*
139+
TestSolution_FindValueOfExpression1
140+
Description:
141+
142+
This function tests whether we can evaluate a simple linear expression
143+
using the solution values.
144+
*/
145+
func TestSolution_FindValueOfExpression1(t *testing.T) {
146+
// Constants
147+
v1 := symbolic.NewVariable()
148+
v2 := symbolic.NewVariable()
149+
150+
tempSol := solution.DummySolution{
151+
Values: map[uint64]float64{
152+
v1.ID: 2.0,
153+
v2.ID: 3.0,
154+
},
155+
Objective: 2.3,
156+
Status: solution_status.OPTIMAL,
157+
}
158+
159+
// Create expression: 2*v1 + 3*v2 = 2*2.0 + 3*3.0 = 4.0 + 9.0 = 13.0
160+
expr := v1.Multiply(symbolic.K(2.0)).Plus(v2.Multiply(symbolic.K(3.0)))
161+
162+
// Algorithm
163+
result, err := solution.FindValueOfExpression(&tempSol, expr)
164+
if err != nil {
165+
t.Errorf("FindValueOfExpression returned an error: %v", err)
166+
}
167+
168+
expected := 13.0
169+
if result != expected {
170+
t.Errorf(
171+
"Expected expression value to be %v; received %v",
172+
expected,
173+
result,
174+
)
175+
}
176+
}
177+
178+
/*
179+
TestSolution_FindValueOfExpression2
180+
Description:
181+
182+
This function tests whether we can evaluate a constant expression.
183+
*/
184+
func TestSolution_FindValueOfExpression2(t *testing.T) {
185+
// Constants
186+
tempSol := solution.DummySolution{
187+
Values: map[uint64]float64{},
188+
Objective: 2.3,
189+
Status: solution_status.OPTIMAL,
190+
}
191+
192+
// Create constant expression: 42.0
193+
expr := symbolic.K(42.0)
194+
195+
// Algorithm
196+
result, err := solution.FindValueOfExpression(&tempSol, expr)
197+
if err != nil {
198+
t.Errorf("FindValueOfExpression returned an error: %v", err)
199+
}
200+
201+
expected := 42.0
202+
if result != expected {
203+
t.Errorf(
204+
"Expected expression value to be %v; received %v",
205+
expected,
206+
result,
207+
)
208+
}
209+
}
210+
211+
/*
212+
TestSolution_FindValueOfExpression3
213+
Description:
214+
215+
This function tests whether we can evaluate an expression with a single variable.
216+
*/
217+
func TestSolution_FindValueOfExpression3(t *testing.T) {
218+
// Constants
219+
v1 := symbolic.NewVariable()
220+
221+
tempSol := solution.DummySolution{
222+
Values: map[uint64]float64{
223+
v1.ID: 5.5,
224+
},
225+
Objective: 2.3,
226+
Status: solution_status.OPTIMAL,
227+
}
228+
229+
// Create expression: v1 + 10 = 5.5 + 10 = 15.5
230+
expr := v1.Plus(symbolic.K(10.0))
231+
232+
// Algorithm
233+
result, err := solution.FindValueOfExpression(&tempSol, expr)
234+
if err != nil {
235+
t.Errorf("FindValueOfExpression returned an error: %v", err)
236+
}
237+
238+
expected := 15.5
239+
if result != expected {
240+
t.Errorf(
241+
"Expected expression value to be %v; received %v",
242+
expected,
243+
result,
244+
)
245+
}
246+
}
247+
248+
/*
249+
TestSolution_FindValueOfExpression4
250+
Description:
251+
252+
This function tests whether we get an error when a variable is missing
253+
from the solution.
254+
*/
255+
func TestSolution_FindValueOfExpression4(t *testing.T) {
256+
// Constants
257+
v1 := symbolic.NewVariable()
258+
v2 := symbolic.NewVariable()
259+
260+
tempSol := solution.DummySolution{
261+
Values: map[uint64]float64{
262+
v1.ID: 2.0,
263+
// v2 is missing
264+
},
265+
Objective: 2.3,
266+
Status: solution_status.OPTIMAL,
267+
}
268+
269+
// Create expression: v1 + v2
270+
expr := v1.Plus(v2)
271+
272+
// Algorithm
273+
_, err := solution.FindValueOfExpression(&tempSol, expr)
274+
if err == nil {
275+
t.Errorf("Expected FindValueOfExpression to return an error for missing variable, but got nil")
276+
}
277+
}
278+
279+
/*
280+
TestSolution_FindValueOfExpression5
281+
Description:
282+
283+
This function tests whether we can evaluate a more complex expression
284+
with multiple operations.
285+
*/
286+
func TestSolution_FindValueOfExpression5(t *testing.T) {
287+
// Constants
288+
v1 := symbolic.NewVariable()
289+
v2 := symbolic.NewVariable()
290+
v3 := symbolic.NewVariable()
291+
292+
tempSol := solution.DummySolution{
293+
Values: map[uint64]float64{
294+
v1.ID: 1.0,
295+
v2.ID: 2.0,
296+
v3.ID: 3.0,
297+
},
298+
Objective: 2.3,
299+
Status: solution_status.OPTIMAL,
300+
}
301+
302+
// Create expression: (v1 + v2) * v3 + 5 = (1.0 + 2.0) * 3.0 + 5 = 3.0 * 3.0 + 5 = 9.0 + 5 = 14.0
303+
expr := v1.Plus(v2).Multiply(v3).Plus(symbolic.K(5.0))
304+
305+
// Algorithm
306+
result, err := solution.FindValueOfExpression(&tempSol, expr)
307+
if err != nil {
308+
t.Errorf("FindValueOfExpression returned an error: %v", err)
309+
}
310+
311+
expected := 14.0
312+
if result != expected {
313+
t.Errorf(
314+
"Expected expression value to be %v; received %v",
315+
expected,
316+
result,
317+
)
318+
}
319+
}

0 commit comments

Comments
 (0)