I wurde mit einem kleinen Multi Ziel Integer Programming Problem spielen:z3 und Interpretation von Punkt-Koeffizienten Floating
In Z3 (die Python-Bindings verwenden) können wir diesen Zustand sehr elegant:
from z3 import *
x1,x2 = Ints('x1 x2')
z1,z2 = Reals('z1 z2')
opt = Optimize()
opt.set(priority='pareto')
opt.add(x1 >= 0, x2 >=0, x1 <= 2, x2 <= 2)
opt.add(x1 <= 2*x2)
# this version is ok:
# opt.add(z1 == x1 - 2*x2, z2 == -x1 + 3*x2)
# this truncates coefficients (round down to integer):
# opt.add(z1 == 0.5*x1 - 1.0*x2, z2 == -0.5*x1 + 1.5*x2)
# this one seems to work:
# opt.add(z1 == 0.5*ToReal(x1) - 1.0*ToReal(x2), z2 == -0.5*ToReal(x1) + 1.5*ToReal(x2))
opt.add(z1 == x1 - 2*x2, z2 == -x1 + 3*x2)
f1 = opt.maximize(z1)
f2 = opt.maximize(z2)
while opt.check() == sat:
print(opt.model())
Dies löst richtig und gibt:
[x1 = 2, x2 = 1, z2 = 1, z1 = 0]
[x1 = 0, x2 = 2, z2 = 6, z1 = -4]
[x1 = 2, x2 = 2, z2 = 4, z1 = -2]
[x1 = 1, x2 = 1, z2 = 2, z1 = -1]
[x1 = 1, x2 = 2, z2 = 5, z1 = -3]
Als mein eigentliches Problem ist für die Ziele Punkt Koeffizienten schwebend, aufgeteilt ich die Ziele von 2:
opt.add(z1 == 0.5*x1 - 1.0*x2, z2 == -0.5*x1 + 1.5*x2)
Dieses Modell sollte die gleichen fünf Lösungen für die x-Variablen geben. Aber wenn wir es laufen, sehen wir einige falsche Ergebnisse:
[x1 = 0, x2 = 0, z2 = 0, z1 = 0]
[x1 = 0, x2 = 2, z2 = 2, z1 = -2]
[x1 = 0, x2 = 1, z2 = 1, z1 = -1]
Wenn ich opt
drucke ich kann sehen, wo die Dinge schief gehen:
(assert (= z1 (to_real (- (* 0 x1) (* 1 x2)))))
(assert (= z2 (to_real (+ (* 0 x1) (* 1 x2)))))
Die Koeffizienten geräuschlos abgeschnitten werden und umgewandelt ganze Zahlen: 0,5 kam als 0 und 1,5 wurde 1.
Eine Abhilfe zu sein scheint:
opt.add(z1 == 0.5*ToReal(x1) - 1.0*ToReal(x2), z2 == -0.5*ToReal(x1) + 1.5*ToReal(x2))
Dieser wandelt die Gleitkomma-Koeffizienten zu ihrer rationalen Äquivalente:
(assert (= z1 (- (* (/ 1.0 2.0) (to_real x1)) (* 1.0 (to_real x2)))))
(assert (= z2 (+ (* (- (/ 1.0 2.0)) (to_real x1)) (* (/ 3.0 2.0) (to_real x2)))))
Nun wird 0.5 und 1.5 durch (/ 1.0 2.0)
(/ 3.0 2.0)
dargestellt ist.
Meine Fragen sind:
- Ist das Abschneiden "wie er entworfen"?
- Ist meine Workaround der richtige Weg, um darüber zu gehen? Oder sollte ich Gleitkomma-Koeffizienten insgesamt vermeiden?
- Die gedruckte rationale Zahl
(/ 1.0 2.0)
scheint darauf hinzuweisen, dass es immer noch Gleitkommazahlen gibt. Ist das wirklich(/ 1 2)
? (Ich nehme an, das sind eigentlich Bigints).
Entschuldigung für meine Ignoranz. Ich habe niemals Arten gesehen, die sich auf diese Weise verengten. Ich denke, ich bin vollkommen von Typ-Promotion statt von Degradierung indoktriniert. –
Siehe meine bearbeitete Antwort. Im Wesentlichen haben die deklarierten Variablen ihre Typen festgelegt, da sie als solche deklariert sind. Und die Konstanten, die Sie einfach verwenden, setzen den Typ voraus, der notwendig ist, um den umgebenden Ausdruck gut typisiert zu machen. Sehr gefährlich in der Tat! Aber das kostet die Arbeit in einer untypisierten Einstellung. –
Vielen Dank. Das ist gut zu wissen. –