How to solve maximum/minimum problems using Z3 SMT-LIB online - optimization

I am trying to solve some maximum/minimum problems using Z3 SMT-LIB online.
One example is:
Find two nonnegative numbers whose sum is 9 and so that the product of one number and the square of the other number is a maximum.
After many attempts the following code was constructed
(define-fun f ((x Real) (y Real)) Real
(if (not (= y 0.0))
(* y (^ x (- y 1)))
0.0))
(declare-const x Real)
(declare-const y Real)
(declare-const z Real)
(declare-const v Real)
(simplify (* x (^ (- 9 x) 2)) :som true)
(assert (= y (* 81.0 (f x 1))))
(assert (= z (* 18.0 (f x 2))))
(assert (= v (f x 3)))
(assert (= z (+ y v )))
(assert (not (= x 0)))
(assert (not (= x 9)))
(set-option :pp-decimal true)
(apply (then simplify solve-eqs))
(check-sat)
(get-model)
The output is:
(+ (* 81.0 x) (* (- 18.0) x x) (* x x x))
(goals
(goal (= (* 36.0 x) (+ (* 81.0 (^ x 0.0)) (* 3.0 (^ x 2.0))))
(not (= x 0.0))
(not (= x 9.0))
:precision precise :depth 2) )
sat
(model
(define-fun x () Real 3.0)
(define-fun v () Real 27.0)
(define-fun z () Real 108.0)
(define-fun y () Real 81.0) )
Run this example online here
Please let me know if you have a more efficient code for this problem. Many thanks.

Related

Is Z3 Max SMT Optimization suited for minimizing violated constraints?

I'm trying to solve a system of linear equations with the additional constraint that each variable should stem from a small finite set of numbers.
In my case however, this cannot be true for all variables as then the there would exist no solution. Thus I tried to formulate it as a Max-SMT problem where I want to maximize the number of variables stemming from their respective set. Doing this for many variables resulted in a far from optimal solution.
An example would be:
(declare-fun B () Int)
(declare-fun A () Int)
(declare-fun D () Int)
(declare-fun C () Int)
(declare-fun E () Int)
(assert (= (- (+ 0 (* 1 C) (* 1 D)) (+ 0 (* 1 A) (* 1 B))) 0))
(assert (= (- (+ 0 (* 1 E)) (+ 0 (* 1 D) (* 2 C))) 0))
(assert (= (- (+ 0 (* 1 D)) (+ 0 (* 1 E) (* 1 A))) 0))
(assert-soft (or (= A 0) (= A 1) (= A 2)) :weight 10)
(assert-soft (or (= B 0) (= B (- 1))) :weight 10)
(assert-soft (or (= C 0) (= C (- 1)) (= C (- 2))) :weight 10)
(assert-soft (or (= D 0) (= D 2)) :weight 10)
(assert-soft (or (= E 5)) :weight 10)
(check-sat)
i.e. for A + B = C + D,
D + 2 C = E and
D = E + A:
A is in {0, 2}, B is in {0, -1}, C is in {0, -1, -2}, D is in {0, 2} and E = 5.
The optimal solution would be A = 2, B = -1, C = -1, D = 2 and E = 0.
For such a small example using Z3's Max-SMT works fine. When I tried scaling this up, using ~1000 variables and 2000 equations the check did return sat but the solution presented (~600 violated clauses) was far worse than a solution I reached using a simple greedy algorithm (~ 50 violated clauses).
Is this not a use-case for Z3 or am I using it wrong? I have used z3py to implement this with, unless stated otherwise, default settings.

Z3 OCaml API Recursive Function

Let's say I want to check if the formula x+y=z (x,y,z integers) is satisfiable. Using Z3 i could input something like:
(declare-fun x () Int)
(declare-fun y () Int)
(declare-fun z () Int)
(assert (= z (+ x y)))
(check-sat)
I could equivalently use the OCaml api and write the following code:
let ctx=Z3.mk_context [("model", "true"); ("proof", "false")] in
let v1=(Z3.Arithmetic.Integer.mk_const_s ctx "x") in
let v2=(Z3.Arithmetic.Integer.mk_const_s ctx "y") in
let res=(Z3.Arithmetic.Integer.mk_const_s ctx "z") in
let sum=Z3.Arithmetic.mk_add ctx [ v1 ; v2] in
let phi=Z3.Boolean.mk_eq ctx sum res in
let solver = (Z3.Solver.mk_solver ctx None) in
let _= Z3.Solver.add solver [phi] in
let is_sat=Z3.Solver.check solver [] in
match is_sat with
| UNSATISFIABLE -> Printf.printf "unsat";
| SATISFIABLE -> Printf.printf "sat";
| UNKNOWN -> Printf.printf "unknown";
I would like to use the ocaml api of z3 to check the satisfiability of
the following factorial implementation, so that I get a value for x (if it exists).
(declare-fun x () Int)
(define-fun-rec f ((x Int)) Int
(ite (> x 1)
(* (f (- x 1))
x)
1))
(assert (= x (f 10)))
(check-sat)
(get-model)
Unfortunately, I can't find an example of recursive definitions using the ml api of z3.

SBCL: Fixnum Optimizations

I'm trying to get more speed out of a little quadratic solver by using optimizations and fixnums. Here's my code:
1: (defun solve-x (d)
2: (declare (optimize (speed 3))
3: (type fixnum d))
4: (let ((x 1) (y 1))
5: (declare (type fixnum x y))
6: (loop while (/= (- (* x x) (* d y y)) 1) do
7: (if (> (- (* x x) (* d y y)) 1)
8: (incf y)
9: (incf x)))
10: (list x y)))
The SBCL compiler seems to have trouble optimizing lines 6 and 7 correctly. I'm getting lots of warnings like this one:
forced to do GENERIC-- (cost 10)
unable to do inline fixnum arithmetic (cost 2) because:
The first argument is a (INTEGER 1 21267647932558653957237540927630737409), not a FIXNUM.
The second argument is a (INTEGER
-98079714615416886892398913872502479823289163909206900736
98079714615416886871131265939943825866051622981576163327), not a FIXNUM.
The result is a (VALUES
(INTEGER
-98079714615416886871131265939943825866051622981576163326
98079714615416886913666561805061133780526704836837638145)
&OPTIONAL), not a (VALUES FIXNUM &REST T).
unable to do inline (signed-byte 64) arithmetic (cost 5) because:
The first argument is a (INTEGER 1 21267647932558653957237540927630737409), not a (SIGNED-BYTE
64).
The second argument is a (INTEGER
-98079714615416886892398913872502479823289163909206900736
98079714615416886871131265939943825866051622981576163327), not a (SIGNED-BYTE
64).
The result is a (VALUES
(INTEGER
-98079714615416886871131265939943825866051622981576163326
98079714615416886913666561805061133780526704836837638145)
&OPTIONAL), not a (VALUES (SIGNED-BYTE 64) &REST T).
etc.
Don't know, where to continue. I already tried to insert 'the fixnum' around multiplications, divisions and subtractions, but it only got worse.
Any ideas, how to make this fast?
If you're sure that the numbers will not overflow at any point, you can add (SAFETY 0) to the optimizations. Also add (THE FIXNUM ...) around the calculations to tell SBCL that you want the result to be treated as a fixnum. The three argument * should be split to two separate calls.
Your code is currently calculating (- (* x x) (* d y y)) twice in the loop. You should assign it to a variable instead. Also notice that since only X or Y changes in the loop, it's unnecessary to calculate the other part again (I don't know what those calculations are, so I just called them FOO, BAR and QUUX).
(defun solve-x (d)
(declare (optimize (speed 3) (safety 0) (debug 0))
(type fixnum d))
(let ((x 1) (y 1))
(declare (type fixnum x y))
(loop with foo of-type fixnum = (* x x)
with bar of-type fixnum = (* (the fixnum (* d y)) y)
for quux of-type fixnum = (- foo bar)
while (/= quux 1)
do (if (> quux 1)
(setf y (1+ y)
bar (* (the fixnum (* d y)) y))
(setf x (1+ x)
foo (* x x))))
(list x y)))
To avoid having to write the formulas twice, you could use the #n= reader macro. X and Y can also be moved to the parameter list as &AUX variables to get rid of the LET and second DECLARE.
(defun solve-x (d &aux (x 1) (y 1))
(declare (optimize (speed 3) (safety 0) (debug 0))
(type fixnum d x y))
(loop with foo of-type fixnum = #1=(* x x)
with bar of-type fixnum = #2=(* d (the fixnum (* y y)))
for quux of-type fixnum = (- foo bar)
while (/= quux 1)
do (if (> quux 1)
(setf y (1+ y)
bar #2#)
(setf x (1+ x)
foo #1#)))
(list x y))
Since X and Y always increase by one, you could avoid some multiplication by incrementing the previous value.
(defun solve-x (d &aux (x 1) (y 1))
(declare (optimize (speed 3) (safety 0) (debug 0))
(type fixnum d x y))
(loop with foo of-type fixnum = 1
with bar of-type fixnum = d
for quux of-type fixnum = (- foo bar)
while (/= quux 1)
do (if (> quux 1)
(setf bar (+ bar (the fixnum (* d y)))
y (1+ y)
bar (+ bar (the fixnum (* d y))))
(setf foo (+ foo x)
x (1+ x)
foo (+ foo x))))
(list x y))
The problem is that fixnum is not a very useful type. In particular, if a and b are fixnums then (* a b) may well not be: consider (* most-positive-fixnum most-positive-fixnum): this is not a fixnum.
So what you need to do is declare the arguments to have good types: in particular types which are enough smaller than a fixnum that the arithmetic will not overflow into bignums. Assuming you're using a 64-bit platform this is reasonably easy.
I don't know how large those numbers can get in your application but by declaring them to be (signed-byte 31) can result in another 25-ish % speed gain.
(deftype int31 (&optional (bits 31)) `(signed-byte ,bits))
(defun solve-x (d &aux (x 1) (y 1))
(declare (optimize (speed 3) (safety 0) (debug 0))
(type int31 d x y))
(loop with foo of-type int31 = 1
with bar of-type int31 = d
for quux of-type int31 = (- foo bar)
while (/= quux 1)
do (if (> quux 1)
(setf bar (+ bar (the int31 (* d y)))
y (1+ y)
bar (+ bar (the int31 (* d y))))
(setf foo (+ foo x)
x (1+ x)
foo (+ foo x))))
(list x y))

Z3 Maximise and Conflicts

I have the following Z3 problem. When the code here is executed, how shall we expect, or how is it defined, that the conflicting optimisation goals will perform?
(declare-const x Bool)
(declare-const y Bool)
(declare-const z Bool)
(maximize(
+
(ite (= y false) 1 0)
(ite (= z false) 1 0)
)
)
(maximize(
+
(ite (= x true) 1 0)
(ite (= y true) 1 0)
(ite (= z true) 1 0)
)
)
(check-sat)
(get-model)
Currently, these are the results:
(+ (ite (= y false) 1 0) (ite (= z false) 1 0)) |-> 2
(+ (ite (= x true) 1 0) (ite (= y true) 1 0) (ite (= z true) 1 0)) |-> 1
sat
(model
(define-fun y () Bool
false)
(define-fun z () Bool
false)
(define-fun x () Bool
true)
)
By default, Z3 solves one optimization goal at a time. It commits one solution and uses the committed solution when solving the next goal. I call this "weak lexicographic" ordering because the committed solution can over-constrain the problem.
You can also configure Z3 to solve the objectives indepdendently or using pareto fronts.
The command-lines are:
(set-option :opt.priority pareto) ; find pareto fronts
(set-option :opt.priority lex) ; weak lexicographic
(set-option :opt.priority box) ; independent

Operator Overloading in Racket / Scheme

I am having some trouble here, and hopefully you guys can help.
Basically, what I am trying to do is overload the + sign in racket so that it will add two vectors instead of two numbers. Also, I want to keep the old + operator so that we can still use it. I know this is supposed to work in scheme, so I was told I needed to use module* to do it in racket. I am still not entirely sure how it all works.
Here is what I have so far:
#lang racket
(module* fun scheme/base
(define old+ +)
(define + new+)
(define (new+ x y)
(cond ((and (vector? x) (vector? y))
(quatplus x y))
(else (old+ x y))))
(define (quatplus x y)
(let ((z (make-vector 4)))
(vector-set! z 0 (old+ (vector-ref x 0) (vector-ref y 0)))
(vector-set! z 1 (old+ (vector-ref x 1) (vector-ref y 1)))
(vector-set! z 2 (old+ (vector-ref x 2) (vector-ref y 2)))
(vector-set! z 3 (old+ (vector-ref x 3) (vector-ref y 3)))
z)))
But it doesn't seem to do anything at all. If anyone knows anything about this I would be very appreciative.
Thank you.
How I would do this is to use the except-in and rename-in specs for require:
#lang racket/base
(require (except-in racket + -)
(rename-in racket [+ old+] [- old-]))
(define (+ x y)
(cond [(and (vector? x) (vector? y))
(quatplus x y)]
[else (old+ x y)]))
(define (quatplus x y)
(vector (+ (vector-ref x 0) (vector-ref y 0))
(+ (vector-ref x 1) (vector-ref y 1))
(+ (vector-ref x 2) (vector-ref y 2))
(+ (vector-ref x 3) (vector-ref y 3))))
(+ (vector 1 2 3 4) (vector 1 2 3 4))
;; => #(2 4 6 8)
You could also use prefix-in with only-in, which would be more convenient if you had many such functions to rename:
(require (except-in racket + -)
(prefix-in old (only-in racket + -)))
A few points:
I had quatplus simply return a new immutable vector (instead of using make-vector and set!). It's simpler and probably faster.
Racket's + accepts any number of arguments. Maybe yours should?
As written, your new + will fail for the combination of a non-vector and a vector. You probably want to fix that:
(+ 1 (vector 1 2 3 4))
; +: contract violation
; expected: number?
; given: '#(1 2 3 4)
; argument position: 1st
; other arguments...:
; 1
You can use Scheme encapsulation to accomplish your needs as:
(import (rename (rnrs) (+ numeric+)))
(define +
(let ((vector+ (lambda (v1 v2) (vector-map numeric+ v1 v2)))
(list+ (lambda (l1 l2) (map numeric+ l1 l2)))
;; …
)
(lambda (a b)
(cond ((and (vector? a) (vector? b)) (vector+ a b))
((and (list? a) (list? b)) (list+ a b))
;; …
(else (numeric+ a b))))))
and if you wanted to work the addition to any depth, this should work:
(define +
(letrec ((vector+ (lambda (v1 v2) (vector-map any+ v1 v2)))
(list+ (lambda (l1 l2) (map any+ l1 l2)))
(any+ (lambda (a b)
(cond ((and (vector? a) (vector? b)) (vector+ a b))
((and (list? a) (list? b)) (list+ a b))
;; …
(else (numeric+ a b))))))
any+))
See:
> (+ (vector (list 1 2) 3) (vector (list 11 12) 13))
#((12 14) 16)