Skip to content

Commit b213888

Browse files
committed
Updated minpresses
1 parent 31f4bed commit b213888

File tree

4 files changed

+439
-0
lines changed

4 files changed

+439
-0
lines changed

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ require (
2727
github.com/emirpasic/gods v1.18.1 // indirect
2828
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
2929
github.com/go-git/go-billy/v5 v5.6.2 // indirect
30+
github.com/golang/glog v1.2.5 // indirect
3031
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
3132
github.com/gorilla/css v1.0.0 // indirect
3233
github.com/inconshreveable/mousetrap v1.1.0 // indirect
3334
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
3435
github.com/kevinburke/ssh_config v1.2.0 // indirect
36+
github.com/mitchellh/go-z3 v0.0.0-20191228203228-4cbedeba863f // indirect
3537
github.com/pjbgf/sha1cd v0.3.2 // indirect
3638
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
3739
github.com/skeema/knownhosts v1.3.1 // indirect
@@ -40,5 +42,6 @@ require (
4042
golang.org/x/crypto v0.45.0 // indirect
4143
golang.org/x/mod v0.19.0 // indirect
4244
golang.org/x/net v0.47.0 // indirect
45+
google.golang.org/protobuf v1.36.10 // indirect
4346
gopkg.in/warnings.v0 v0.1.2 // indirect
4447
)

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3c
5050
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
5151
github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y=
5252
github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
53+
github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I=
54+
github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
5355
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
5456
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
5557
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
@@ -75,6 +77,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
7577
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
7678
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
7779
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
80+
github.com/mitchellh/go-z3 v0.0.0-20191228203228-4cbedeba863f h1:I2Rx8N5cDzVL4amj76w9F+fRS5zvZdmMyphvPMA+HJQ=
81+
github.com/mitchellh/go-z3 v0.0.0-20191228203228-4cbedeba863f/go.mod h1:SCzzTuqNJ1cVcftwEustt+uZcgDQhp0lJnWQPU3a3Lw=
7882
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
7983
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
8084
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
@@ -197,6 +201,8 @@ golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0
197201
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
198202
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
199203
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
204+
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
205+
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
200206
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
201207
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
202208
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

utils/minpresses/gauss.go

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
package minpresses
2+
3+
// SolveMinPressesOptimized uses Gaussian elimination like the reference solution
4+
func SolveMinPressesOptimized(buttonPositions [][]int, targetJoltages []int) (int, bool) {
5+
n := len(buttonPositions) // number of buttons
6+
m := len(targetJoltages) // number of positions
7+
8+
// Build coefficient matrix: matrix[i][j] = 1 if button j affects position i
9+
matrix := make([][]int, m)
10+
for i := range matrix {
11+
matrix[i] = make([]int, n+1) // +1 for the constant term
12+
for j := 0; j < n; j++ {
13+
affects := false
14+
for _, pos := range buttonPositions[j] {
15+
if pos == i {
16+
affects = true
17+
break
18+
}
19+
}
20+
if affects {
21+
matrix[i][j] = 1
22+
}
23+
}
24+
matrix[i][n] = targetJoltages[i] // constant term
25+
}
26+
27+
// Perform Gaussian elimination
28+
pivotCols, reducedMatrix := gaussianElimination(matrix)
29+
if reducedMatrix == nil {
30+
return 0, false
31+
}
32+
33+
// Identify pivot (constrained) and free (unconstrained) variables
34+
pivotSet := make(map[int]bool)
35+
for _, col := range pivotCols {
36+
pivotSet[col] = true
37+
}
38+
39+
freeVars := []int{}
40+
for i := 0; i < n; i++ {
41+
if !pivotSet[i] {
42+
freeVars = append(freeVars, i)
43+
}
44+
}
45+
46+
bestSolution := make([]int, n)
47+
bestSum := -1
48+
49+
// Try different values for free variables and back-substitute
50+
var trySolution func(freeValues []int)
51+
trySolution = func(freeValues []int) {
52+
solution := make([]int, n)
53+
54+
// Set free variables
55+
for i, varIdx := range freeVars {
56+
if i < len(freeValues) {
57+
solution[varIdx] = freeValues[i]
58+
}
59+
}
60+
61+
// Back-substitute to find pivot variables
62+
for i := len(pivotCols) - 1; i >= 0; i-- {
63+
row := i
64+
col := pivotCols[i]
65+
total := reducedMatrix[row][n] // constant term
66+
67+
for j := col + 1; j < n; j++ {
68+
total -= reducedMatrix[row][j] * solution[j]
69+
}
70+
71+
if reducedMatrix[row][col] == 0 {
72+
return // Can't solve
73+
}
74+
75+
if total%reducedMatrix[row][col] != 0 {
76+
return // Not an integer solution
77+
}
78+
79+
val := total / reducedMatrix[row][col]
80+
if val < 0 {
81+
return // Negative solution not valid
82+
}
83+
84+
solution[col] = val
85+
}
86+
87+
// Verify the solution satisfies all equations
88+
for i := 0; i < m; i++ {
89+
total := 0
90+
for j := 0; j < n; j++ {
91+
if solution[j] > 0 {
92+
for _, pos := range buttonPositions[j] {
93+
if pos == i {
94+
total += solution[j]
95+
break
96+
}
97+
}
98+
}
99+
}
100+
if total != targetJoltages[i] {
101+
return // Solution doesn't satisfy this equation
102+
}
103+
}
104+
105+
// Calculate total presses
106+
totalPresses := 0
107+
for _, val := range solution {
108+
totalPresses += val
109+
}
110+
111+
// Keep the best solution
112+
if bestSum == -1 || totalPresses < bestSum {
113+
copy(bestSolution, solution)
114+
bestSum = totalPresses
115+
}
116+
}
117+
118+
// Enumerate small values for free variables
119+
maxVal := 0
120+
for _, j := range targetJoltages {
121+
if j > maxVal {
122+
maxVal = j
123+
}
124+
}
125+
126+
if len(freeVars) == 0 {
127+
trySolution([]int{})
128+
} else if len(freeVars) == 1 {
129+
limit := maxVal * 3
130+
for val := 0; val <= limit; val++ {
131+
if bestSum != -1 && val > bestSum {
132+
break
133+
}
134+
trySolution([]int{val})
135+
}
136+
} else if len(freeVars) == 2 {
137+
limit := maxVal
138+
if limit < 200 {
139+
limit = 200
140+
}
141+
for v1 := 0; v1 <= limit; v1++ {
142+
for v2 := 0; v2 <= limit; v2++ {
143+
if bestSum != -1 && v1+v2 > bestSum {
144+
continue
145+
}
146+
trySolution([]int{v1, v2})
147+
}
148+
}
149+
} else if len(freeVars) == 3 {
150+
for v1 := 0; v1 < 250; v1++ {
151+
for v2 := 0; v2 < 250; v2++ {
152+
for v3 := 0; v3 < 250; v3++ {
153+
if bestSum != -1 && v1+v2+v3 > bestSum {
154+
continue
155+
}
156+
trySolution([]int{v1, v2, v3})
157+
}
158+
}
159+
}
160+
} else if len(freeVars) == 4 {
161+
for v1 := 0; v1 < 30; v1++ {
162+
for v2 := 0; v2 < 30; v2++ {
163+
for v3 := 0; v3 < 30; v3++ {
164+
for v4 := 0; v4 < 30; v4++ {
165+
if bestSum != -1 && v1+v2+v3+v4 > bestSum {
166+
continue
167+
}
168+
trySolution([]int{v1, v2, v3, v4})
169+
}
170+
}
171+
}
172+
}
173+
} else {
174+
// Too many free variables - try just zeros
175+
trySolution(make([]int, len(freeVars)))
176+
}
177+
178+
if bestSum == -1 {
179+
return 0, false
180+
}
181+
182+
return bestSum, true
183+
}
184+
185+
// gaussianElimination performs Gaussian elimination and returns pivot columns and reduced matrix
186+
func gaussianElimination(matrix [][]int) ([]int, [][]int) {
187+
m := len(matrix)
188+
if m == 0 {
189+
return nil, nil
190+
}
191+
n := len(matrix[0]) - 1 // Exclude constant column
192+
193+
// Make a copy of the matrix
194+
reducedMatrix := make([][]int, m)
195+
for i := range reducedMatrix {
196+
reducedMatrix[i] = make([]int, len(matrix[i]))
197+
copy(reducedMatrix[i], matrix[i])
198+
}
199+
200+
pivotCols := []int{}
201+
row := 0
202+
203+
for col := 0; col < n && row < m; col++ {
204+
// Find pivot
205+
pivotRow := -1
206+
for r := row; r < m; r++ {
207+
if reducedMatrix[r][col] != 0 {
208+
pivotRow = r
209+
break
210+
}
211+
}
212+
213+
if pivotRow == -1 {
214+
continue // No pivot in this column
215+
}
216+
217+
// Swap rows
218+
if pivotRow != row {
219+
reducedMatrix[row], reducedMatrix[pivotRow] = reducedMatrix[pivotRow], reducedMatrix[row]
220+
}
221+
222+
pivotCols = append(pivotCols, col)
223+
224+
// Eliminate below pivot
225+
for r := row + 1; r < m; r++ {
226+
if reducedMatrix[r][col] != 0 {
227+
// Scale and subtract
228+
factor := reducedMatrix[r][col] / reducedMatrix[row][col]
229+
for c := col; c <= n; c++ {
230+
reducedMatrix[r][c] -= factor * reducedMatrix[row][c]
231+
}
232+
}
233+
}
234+
235+
row++
236+
}
237+
238+
return pivotCols, reducedMatrix
239+
}

0 commit comments

Comments
 (0)