49 lines
1.4 KiB
Go
49 lines
1.4 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|||
|
|
// SPDX-License-Identifier: MIT
|
||
|
|
|
||
|
|
package optim
|
||
|
|
|
||
|
|
import (
|
||
|
|
"math"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"sourcedock.dev/petrbalvin/tensor/internal/core"
|
||
|
|
)
|
||
|
|
|
||
|
|
// MinimiseLinearRows hands both standard rows of a two-sided constraint
|
||
|
|
// slots in the one backing block, taken in build order. A fixture with
|
||
|
|
// a two-sided row and a one-sided row pins the hand-computed optimum,
|
||
|
|
// which a row that aliased its neighbour could not reach.
|
||
|
|
|
||
|
|
func TestMinimiseLinearRowsTwoSidedConstraint(t *testing.T) {
|
||
|
|
// minimise x1 - 2*x2 over 2 ≤ x1 + x2 ≤ 3 and 0 ≤ x1 ≤ 1: the
|
||
|
|
// objective pushes x2 up and x1 down, so x1 = 0, x2 = 3 and the
|
||
|
|
// optimum is -6.
|
||
|
|
cost, err := core.FromFloats([]float64{1, -2}, 2)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("FromFloats: %v", err)
|
||
|
|
}
|
||
|
|
a, err := core.FromFloats([]float64{1, 1, 1, 0}, 2, 2)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("FromFloats: %v", err)
|
||
|
|
}
|
||
|
|
cons := LinearConstraints{
|
||
|
|
A: a,
|
||
|
|
Lower: []float64{2, 0},
|
||
|
|
Upper: []float64{3, 1},
|
||
|
|
}
|
||
|
|
x, value, merr := MinimiseLinearRows(cost, cons, LinearProgramOptions{})
|
||
|
|
if merr != nil {
|
||
|
|
t.Fatalf("MinimiseLinearRows: %v", merr)
|
||
|
|
}
|
||
|
|
if math.Abs(value+6) > 1e-9 {
|
||
|
|
t.Fatalf("optimum = %v, want -6", value)
|
||
|
|
}
|
||
|
|
if v := x.FloatAt(0); math.Abs(v) > 1e-9 {
|
||
|
|
t.Fatalf("x1 = %v, want 0", v)
|
||
|
|
}
|
||
|
|
if v := x.FloatAt(1); math.Abs(v-3) > 1e-9 {
|
||
|
|
t.Fatalf("x2 = %v, want 3", v)
|
||
|
|
}
|
||
|
|
}
|