Is there anyone, who can help me with my smt homework? - smt

Homework:
Lab 4
In the second SMT lab exercise (Lab 4) we are going to solve the Chicken McNugget problem with the help of an SMT solver (an instance of the Frobenious Coin Problem).
Assume that a fast food chain sells boxes with fried chicken pieces in the sizes A=7, B= 9, C=16. Your friends and you are hungry and want to eat X chicken pieces (a natural number). The first question we are going to address is whether it is possible to buy U boxes of size A, V boxes of size B and W boxes of size C such that you get exactly X chicken pieces (without left over). In the first part (1 point) formulate this as an SMT problem and try to solve it for the given A, B, C values and X=40. First determine the logic you need and then give a manual incoding into SMT lib. In the second part (1.5 point) check that X0 = X+0, ..., X6 = X + 6 also have similar representations in terms of U0,V0,W0, ..., U6,V6,W6. With the help of this encoding determine the minimal number X which gives a satisfiable solution. Then Y=X-1 is the solution of the Chicken McNuggets problem for the fixed A, B, C values above, which means that it is the largest number Y which can NOT be represented this way, or in terms of chicken pieces, no matter how many (U,V,W) boxes of the given sizes (A,B,C) you buy and your friends do eat exactly Y pieces, then there has to be some left over pieces. Generating these two SMT LIB encodings for these two parts for the given concrete A,B,C and being able to present the solution (and modify and check it manually for other values) will give you thus half the points (2.5) for the Lab. You will be required to bring your own laptop on which you have installed and can use the SMT solver for the presentation (the web interface is not enough).
My SMT Code:
(set-logic QF_AUFNIA)
(declare-const u Int)
(declare-const v Int)
(declare-const w Int)
(declare-const x Int)
(assert (>= u 0))
(assert (>= v 0))
(assert (>= w 0))
(assert (= 40(+ (* u 7)(* v 9)(* w 16))))
(assert (= 40(+ (* u 7)(* v 9))))
(assert (= 40(+ (* v 9)(* w 16))))
(assert (= 40(+ (* u 7)(* w 16))))
(assert (= 40(* v 9)))
(assert (= 40(* u 7)))
(assert (= 40(* w 16)))
(declare-const x0 Int)
(declare-const x1 Int)
(declare-const x2 Int)
(declare-const x3 Int)
(declare-const x4 Int)
(declare-const x5 Int)
(declare-const x6 Int)
(declare-const u0 Int)
(declare-const u1 Int)
(declare-const u2 Int)
(declare-const u3 Int)
(declare-const u4 Int)
(declare-const u5 Int)
(declare-const u6 Int)
(declare-const v0 Int)
(declare-const v1 Int)
(declare-const v2 Int)
(declare-const v3 Int)
(declare-const v4 Int)
(declare-const v5 Int)
(declare-const v6 Int)
(declare-const w0 Int)
(declare-const w1 Int)
(declare-const w2 Int)
(declare-const w3 Int)
(declare-const w4 Int)
(declare-const w5 Int)
(declare-const w6 Int)
(declare-const y Int)
(assert (= x0 (+ x 0)))
(assert (= x1 (+ x 1)))
(assert (= x2 (+ x 2)))
(assert (= x3 (+ x 3)))
(assert (= x4 (+ x 4)))
(assert (= x5 (+ x 5)))
(assert (= x6 (+ x 6)))
(assert (= u0 (+ u 0)))
(assert (= u1 (+ u 1)))
(assert (= u2 (+ u 2)))
(assert (= u3 (+ u 3)))
(assert (= u4 (+ u 4)))
(assert (= u5 (+ u 5)))
(assert (= u6 (+ u 6)))
(assert (= v0 (+ v 0)))
(assert (= v1 (+ v 1)))
(assert (= v2 (+ v 2)))
(assert (= v3 (+ v 3)))
(assert (= v4 (+ v 4)))
(assert (= v5 (+ v 5)))
(assert (= v6 (+ v 6)))
(assert (= w0 (+ w 0)))
(assert (= w1 (+ w 1)))
(assert (= w2 (+ w 2)))
(assert (= w3 (+ w 3)))
(assert (= w4 (+ w 4)))
(assert (= w5 (+ w 5)))
(assert (= w6 (+ w 6)))
(assert (= x 40))
(assert (= x (+ (* u 7)(* v 9)(* w 16))))
(check-sat)
(exit)
I wrote my code, but it is always unsatisfiable. It is said, that X should be satisfiable. I tried X almost with every figure to get it satisfiable, but it doesn't work.
Is there anyone who could help me?

You're getting unsat for a very simple reason. Consider this line:
(assert (= 40(* u 7)))
where u is an Int value. Z3 can easily determine that there is no such integer value, as 7 does not divide 40. Similarly, you have many other constraints that are just not satisfiable for similar reasons.
Here's a simple idea to push forward. If someone gave you u, v, and w values and asked you to just check that they are indeed a correct solution, how would you program that? Write down what properties these values would have to satisfy, and simply assert them. Through the magic of constraint solving, what you'd consider "checking" a solution will become "finding" the solution. Hope that helps!
Also, stack-overflow works the best when you ask specific and pointed questions, instead of dumping an entire problem set. You'll get much better answers if you ask specific questions. Best of luck!

Related

Holding greater or equal relation between two terms

H:count k (match d with
|nil=>nil
|s::l=>(s::firstn n l))
end <=
count 0 (match d with
|nil=>nil
|s::l=>(s::firstn n l))
end
Where n is natural number and d is list nat. From above H may i extract information that (s::firstn n l) contains more zeros than k.

How to use Coq arithmetic solver tactics with SSReflect arithmetic statements

Coq has some convenient tactics for automatically proving arithmetic lemmas, for instance lia:
From Coq Require Import ssreflect ssrfun ssrbool.
From mathcomp Require Import ssrnat.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Require Import Psatz.
Lemma obv : forall (x y z: nat), (x < y)%coq_nat -> (y < z)%coq_nat -> (z < 3)%coq_nat -> (x < 3)%coq_nat.
Proof.
move => x y z xlty yltz zlt3. lia.
Qed.
The tactics do not directly support SSReflect-style boolean reflection statements however:
Lemma obv_ssr: forall (x y z: nat), (x < y) && (y < z) && (z < 3) -> (x < 3).
Proof.
move => x y z H. Fail lia.
Abort.
Lemma obv_ssr: forall (x y z: nat), (x < y) -> (y < z) -> (z < 3) -> (x < 3).
Proof.
move => x y z xlty yltz zlt3. Fail lia.
Abort.
It's possible to solve them by converting to non-SSR format using views:
Lemma obv_ssr: forall (x y z: nat), (x < y) && (y < z) && (z < 3) -> (x < 3).
Proof.
move => x y z. move/andP => [/andP [/ltP x_lt_y /ltP y_lt_z] /ltP z_lt_3].
apply/ltP. lia.
Qed.
This is however very manual. Is there some kind of technique/approach/tactic that can automate this application of lemmas like lia to SSR-style statements?
This is not yet a totally resolved issue in general: you can track its progress here.
In your particular example the following is enough:
Lemma obv_ssr: forall (x y z: nat), (x < y) && (y < z) && (z < 3) -> (x < 3).
Proof.
move=> x y z.
rewrite -?(rwP andP) -?(rwP ltP).
lia.
Qed.
Sometimes you might want to throw in some more conversions of the standard arithmetic types using something like rewrite -?plusE -?multE -?minusE (adding more conversions if you have more arithmetic operations in your goal).
There are at least two projects trying to resolve the issue in general:
https://github.com/amahboubi/lia4mathcomp (see ssrnatlia tactic there, but I unless I'm mistaken it cannot solve your goal).
https://github.com/pi8027/mczify -- an active project with a different architecture and as far as I know it should be capable of solving a lot of SSReflect-style goals.

define: expected only one expression for the function body, but found 1 extra part

I got an error. Can someone help me please?
define: expected only one expression for the function body, but found 1 extra part
(sqrt (+ (* (- x2 x1) (- x2 x1)) (* (- y2 y1) (- y2 y1))))
(if( < circles-position abs(- r1 r2) "Interior" if(< (+ r1 r2) d) "External" "Intersect")))
The body of function must in the teaching languages be one expression only.
Above you have two expressions.
It's easier to read your code, if you indent if on three lines:
(sqrt (+ (* (- x2 x1) (- x2 x1))
(* (- y2 y1) (- y2 y1))))
(if (< circles-position (abs (- r1 r2)))
"Interior"
(if (< (+ r1 r2) d)
"External"
"Intersect")))

How do i get Cosine Product approximation to work in Racket?

For homework, I have to write a function which presents a product approximation of the cosine function which recurses until the difference between the current and newly calculated product is less than a threshold.
(define (p_cos x)
(let* ([n 1]
[xnew (* x (p_cos_aux x (+ n 1)))])
(if (< (abs (- x xnew)) TOL)
x
(p_cos_aux xnew (+ n 1)))))
(define (p_cos_aux x n)
(- 1 (/ (* 4 (square x)) (* (square pi) (square (- (* 2 n) 1))))))
the values are expected to be:
(p_cos 0)
=> 1
(p_cos (/ pi 2))
=> 0
however I am getting:
> (p_cos (/ pi 2))
0.9122085048010974
> (p_cos 0)
0
Can anyone explain to me why my outputs are so far from the expected values?
I'm basing my code off of this infinite product formula for approximations of cosine:
cos(x) = ∏n=1n→∞ [ 1 − (4x2)/(π2(2n - 1)2) ]
Since you're basing this on this math formula:
cos(x) = ∏n=1n→∞ [ 1 − (4x2)/(π2(2n - 1)2) ]
It looks like your p_cos_aux function is handling the stuff inside the square brackets in the formula. So you still need to define cosine to be equal to
cos(x) = ∏n=1n→∞ (p_cos_aux x n)
If you want your code to return an answer, then you should to do this for only a finite number n. You can do this with either recursion or a for loop. In this case, Racket's for/product loop is convenient:
(for/product ([n (in-range 1 ...some-large-number...)])
(p_cos_aux x n))
Let's try putting in 100 for the large number:
(define (p_cos x)
(for/product ([n (in-range 1 100)])
(p_cos_aux x n)))
Trying it out:
> (p_cos 0)
1
> (p_cos (* 1/4 pi))
0.707553324600212
> (p_cos (* 1/2 pi))
0.0
> (p_cos (* 3/4 pi))
-0.7111358730792002
> (p_cos pi)
-1.01015228426396
> (p_cos (* 5/4 pi))
-0.7183556654338034
> (p_cos (* 3/2 pi))
-0.0
> (p_cos (* 7/4 pi))
0.7293234913165205
> (p_cos (* 2 pi))
1.0412338930105425
It's not perfect, but you can get better approximations by increasing the 100 to even larger numbers.

Degree of polynomial smaller than a number

I am working on a lemma that shows that the degree of a sum of monomials is always less or equal to n if the exponent of each monomial is less or equal to n.
lemma degree_poly_smaller:
fixes a :: "('a::comm_ring_1 poly)" and n::nat
shows "degree (∑x∷nat | x ≤ n . monom (coeff a x) x) ≤ n"
sorry
What I have to so far is the following (please mind that I am a beginner in Isabelle):
lemma degree_smaller:
fixes a :: "('a::comm_ring_1 poly)" and n::nat
shows "degree (∑x∷nat | x ≤ n . monom (coeff a x) x) ≤ n"
proof-
have th01: "⋀k. k ≤ n ⟹
degree (setsum (λ x . monom (coeff a x) k) {x∷nat. x ≤ n}) ≤ n"
by (metis degree_monom_le monom_setsum order_trans)
have min_lemma1: "k∈{x∷nat. x ≤ n} ⟹ k ≤ n" by simp
from this th01 have th02:
"⋀k. k∈{x∷nat. x ≤ n} ⟹
degree (setsum (λ x . monom (coeff a x) k) {x∷nat. x ≤ n}) ≤ n"
by (metis mem_Collect_eq)
have min_lemma2: "(SOME y . y ≤ n) ≤ n" by (metis (full_types) le0 some_eq_ex)
from this have th03:
"degree (∑x∷nat | x ≤ n . monom (coeff a x) (SOME y . y ≤ n)) ≤ n"
by (metis th01)
from min_lemma1 min_lemma2 have min_lemma3:
"(SOME y . y∈{x∷nat. x ≤ n}) ≤ n" by (metis (full_types) mem_Collect_eq some_eq_ex)
from this th01 th02 th03 have th04:
"degree (∑x∷nat | x ≤ n . monom (coeff a x) (SOME y . y∈{x∷nat. x ≤ n}) ) ≤ n"
by presburger
Here is the problem, I don't understand why the following lemma is not sufficient to finish the proof. In particular, I would expect the last part (where the sorry is) to be simple enough for sledgehammer to find a proof:
from this th01 th02 th03 th04 have th05:
"degree
(setsum (λ i . monom (coeff a i) (SOME y . y∈{x∷nat. x ≤ n})) {x∷nat. x ≤ n})
≤ n"
by linarith
(* how can I prove this last step ? *)
from this have
"degree (setsum (λ i . monom (coeff a i) i) {x∷nat. x ≤ n}) ≤ n" sorry
from this show ?thesis by auto
qed
.
SOLUTION from Brian Huffman's excellent answer:
.
lemma degree_setsum_smaller:
"finite A ⟹ ∀x∈A. degree (f x) ≤ n ⟹ degree (∑x∈A. f x) ≤ n"
apply(induct rule: finite_induct)
apply(auto)
by (metis degree_add_le)
lemma finiteSetSmallerThanNumber:
"finite {x∷nat. x ≤ n}"
by (metis finite_Collect_le_nat)
lemma degree_smaller:
fixes a :: "('a::comm_ring_1 poly)" and n::nat
shows "degree (∑x∷nat | x ≤ n . monom (coeff a x) x) ≤ n"
apply (rule degree_setsum_smaller)
apply(simp add: finiteSetSmallerThanNumber)
by (metis degree_0 degree_monom_eq le0 mem_Collect_eq monom_eq_0_iff) (* from sledgehammer *)
The last step does not follow from your th05. The problem is that you seem to want to unify (SOME y. y∈{x∷nat. x ≤ n}) with the bound variable i. However, in HOL (SOME y. y∈{x∷nat. x ≤ n}) has a single value that depends only on n and not on i. Furthermore, you don't get to choose the value; a theorem using SOME is not the same as a theorem with a universally quantified variable.
My advice is to avoid using SOME altogether, and instead try to prove a generalization of your theorem first:
lemma degree_setsum_smaller:
"finite A ⟹ ∀x∈A. degree (f x) ≤ n ⟹ degree (∑x∈A. f x) ≤ n"
You should be able to prove degree_setsum_smaller by induction over A (use induct rule: finite_induct), and then use it to prove degree_poly_smaller. Lemma degree_add_le from the polynomial library should be useful.
It is generally considered bad style to use auto as anything other than the last method in an apply script, because such proofs tend to be quite fragile. I would eliminate the "finiteSetSmallerThanNumber" lemma completely, it is a needlessly specific special case of Collect_le_nat. Also, camel case names for theorems are usually not used in Isabelle.
At any rate, this is my suggestion of how to make the proofs nicer:
lemma degree_setsum_smaller:
"finite A ⟹ ∀x∈A. degree (f x) ≤ n ⟹ degree (∑x∈A. f x) ≤ n"
by (induct rule: finite_induct, simp_all add: degree_add_le)
lemma degree_smaller:
fixes a :: "('a::comm_ring_1 poly)" and n::nat
shows "degree (∑x∷nat | x ≤ n . monom (coeff a x) x) ≤ n"
proof (rule degree_setsum_smaller)
show "finite {x. x ≤ n}" using finite_Collect_le_nat .
{
fix x assume "x ≤ n"
hence "degree (monom (coeff a x) x) ≤ n"
by (cases "coeff a x = 0", simp_all add: degree_monom_eq)
}
thus "∀x∈{x. x≤ n}. degree (monom (coeff a x) x) ≤ n" by simp
qed