How to solve nqueen problem with Z3 solver - z3

I write a formula to solve nqueen problem. It finds one of the solution but I want find all solution how I generalize to all solution for this formula:
from z3 import *
import time
def queens(n,all=0):
start = time.time()
sol = Solver()
# q = [Int("q_%s" % (i)) for i in range(n) ] # n=100: ???s
# q = IntVector("q", n) # this is much faster # n=100: 28.1s
q = Array("q", IntSort(), BitVecSort(8)) # n=100: ??s
# Domains
sol.add([And(q[i]>=0, q[i] <= n-1) for i in range(n)])
# Constraints
for i in range(n):
for j in range(i):
sol.add(q[i] != q[j], q[i]+i != q[j]+j, q[i]-i != q[j]-j)
if sol.check() == sat:
mod = sol.model()
ss = [mod.evaluate(q[i]) for i in range(n)]
print(ss)
# Show all solutions
if all==1:
num_solutions = 0
while sol.check() == sat:
m = sol.model()
ss = [mod.evaluate(q[i]) for i in range(n)]
sol.add( Or([q[i] != ss[i] for i in range(n)]) )
print("q=",ss)
num_solutions = num_solutions + 1
print("num_solutions:", num_solutions)
else:
print("failed to solve")
end = time.time()
value = end - start
print("Time: ", value)
for n in [8,10,12,20,50,100,200]:
print("Testing ", n)
queens(n,0)
For N=4 I try to show 2 solution
For N=8 I try to show all 92 solution

You got most of it correct, though there are issues with how you coded the find-all-solutions part. There's a solution for N-queens that comes with the z3 tutorial here: https://ericpony.github.io/z3py-tutorial/guide-examples.htm
You can turn it into an "find-all-solutions" versions like this:
from z3 import *
def queens(n):
Q = [Int('Q_%i' % (i + 1)) for i in range(n)]
val_c = [And(1 <= Q[i], Q[i] <= n) for i in range(n)]
col_c = [Distinct(Q)]
diag_c = [If(i == j, True, And(Q[i] - Q[j] != i - j, Q[i] - Q[j] != j - i)) for i in range(n) for j in range(i)]
sol = Solver()
sol.add(val_c + col_c + diag_c)
num_solutions = 0
while sol.check() == sat:
mod = sol.model()
ss = [mod.evaluate(Q[i]) for i in range(n)]
print(ss)
num_solutions += 1
sol.add(Or([Q[i] != ss[i] for i in range(n)]))
print("num_solutions:", num_solutions)
queens(4)
queens(8)
This'll print 2 solutions for N=4 and 92 for N=8.

Related

Applying Lookahead with z3 Solver

I want to solve a CSP with the help of Lookahead method in z3 Solver. The issue I'm facing is not being convinced that it's invoked by setting an according parameter like s.set("sat.lookahead_simplify", True) or s.set("sat.lookahead.delta_fraction", 0.7).
Below is the code for solving my combinatorial problem. I ren a similar solver on a complex instance A and the runtime without these settings on Lookahead was 3674 seconds versus 3670 secunds with these settings. So, seems like they have no effect.
Does anyone know how to correctly invoke Lookahead here?
import numpy as np
import timeit
from z3 import *
def as_long(self):
if z3_debug():
_z3_assert(self.is_int(), "Integer value expected")
return int(self.as_string())
def model_int(mo, R, C, m, n):
R_int = [mo[R[i]].as_long() for i in range(m)]
C_int = [mo[C[j]].as_long() for j in range(n)]
return [R_int, C_int] # integer model values
def CSP(A, D, bit_length=8):
A_shape = A.shape
m = A_shape[0]
n = A_shape[1]
#initialize solver
s = Solver()
s.set("lookahead_simplify", True)
s.set("sat.lookahead.delta_fraction", 0.7)
#initialize column and row variables c_j and r_i as bit vectors
C = [BitVec(f"c_{j + 1}", bit_length) for j in range(n)]
R = [BitVec(f"r_{i + 1}", bit_length) for i in range(m)]
#initialize search space restriction constraints for r_i's as lists
Constr_D = [Or([r == d for d in D]) for r in R]
#initialize permit-constraints as lists
Constr_permit = [R[i] & C[j] == C[j] for i in range(m) for j in range(n) if A[i,j]]
Constr_npermit = [R[i] & C[j] != C[j] for i in range(m) for j in range(n) if not A[i,j]]
#add constraints
s.add(Constr_D + Constr_permit + Constr_npermit)
#search solution
check = s.check()
if check == sat:
return model_int(s.model(), R, C, m, n)
return check
# model instance ........
D = [7,11,19,35,67,13,21,37,69,25,41,73,49,81,82,84,88] #domain
m = 15 #number of rows
n = 9 #number of columns
p=.11
A = np.random.choice(a=[1,0],size=(m,n),p=[p,1-p])
print(A)
# executing solver on model instance ........
starttime = timeit.default_timer()
print(CSP(A,D))
print("The time difference is :", timeit.default_timer() - starttime)

math library is missing in the latest update of Logitech G-Hub

local delay = math.random(25, 50)
[string "LuaVM"]:5: attempt to index a nil value (global 'math')
I can't use math.random anymore is there any way to fix this ?
If math library is missed you can insert the following code block at the beginning of your script.
It will not fix the whole math library, but only some of the most frequently used functions (including math.random).
It will also fix the following errors:
bad argument #1 to 'Sleep' (number has no integer representation)
attempt to call a nil value (field 'getn')
do
local state_8, state_45, cached_bits, cached_bits_qty = 2, 0, 0, 0
local prev_width, prev_bits_in_factor, prev_k = 0
for c in GetDate():gmatch"." do
state_45 = state_45 % 65537 * 23456 + c:byte()
end
local function get_53_random_bits()
local value53 = 0
for shift = 26, 27 do
local p = 2^shift
state_45 = (state_45 * 233 + 7161722017421) % 35184372088832
repeat state_8 = state_8 * 76 % 257 until state_8 ~= 1
local r = state_8 % 32
local n = state_45 / 2^(13 - (state_8 - r) / 32)
n = (n - n%1) % 2^32 / 2^r
value53 = value53 * p + ((n%1 * 2^32) + (n - n%1)) % p
end
return value53
end
for j = 1, 10 do get_53_random_bits() end
local function get_random_bits(number_of_bits)
local pwr_number_of_bits = 2^number_of_bits
local result
if number_of_bits <= cached_bits_qty then
result = cached_bits % pwr_number_of_bits
cached_bits = (cached_bits - result) / pwr_number_of_bits
else
local new_bits = get_53_random_bits()
result = new_bits % pwr_number_of_bits
cached_bits = (new_bits - result) / pwr_number_of_bits * 2^cached_bits_qty + cached_bits
cached_bits_qty = 53 + cached_bits_qty
end
cached_bits_qty = cached_bits_qty - number_of_bits
return result
end
table = table or {}
table.getn = table.getn or function(x) return #x end
math = math or {}
math.huge = math.huge or 1/0
math.abs = math.abs or function(x) return x < 0 and -x or x end
math.floor = math.floor or function(x) return x - x%1 end
math.ceil = math.ceil or function(x) return x + (-x)%1 end
math.min = math.min or function(x, y) return x < y and x or y end
math.max = math.max or function(x, y) return x > y and x or y end
math.sqrt = math.sqrt or function(x) return x^0.5 end
math.pow = math.pow or function(x, y) return x^y end
math.frexp = math.frexp or
function(x)
local e = 0
if x == 0 then
return x, e
end
local sign = x < 0 and -1 or 1
x = x * sign
while x >= 1 do
x = x / 2
e = e + 1
end
while x < 0.5 do
x = x * 2
e = e - 1
end
return x * sign, e
end
math.exp = math.exp or
function(x)
local e, t, k, p = 0, 1, 1
repeat e, t, k, p = e + t, t * x / k, k + 1, e
until e == p
return e
end
math.log = math.log or
function(x)
assert(x > 0)
local a, b, c, d, e, f = x < 1 and x or 1/x, 0, 0, 1, 1
repeat
repeat
c, d, e, f = c + d, b * d / e, e + 1, c
until c == f
b, c, d, e, f = b + 1 - a * c, 0, 1, 1, b
until b <= f
return a == x and -f or f
end
math.log10 = math.log10 or
function(x)
return math.log(x) / 2.3025850929940459
end
math.random = math.random or
function(m, n)
if m then
if not n then
m, n = 1, m
end
local k = n - m + 1
if k < 1 or k > 2^53 then
error("Invalid arguments for function 'random()'", 2)
end
local width, bits_in_factor, modk
if k == prev_k then
width, bits_in_factor = prev_width, prev_bits_in_factor
else
local pwr_prev_width = 2^prev_width
if k > pwr_prev_width / 2 and k <= pwr_prev_width then
width = prev_width
else
width = 53
local width_low = -1
repeat
local w = (width_low + width) / 2
w = w - w%1
if k <= 2^w then
width = w
else
width_low = w
end
until width - width_low == 1
prev_width = width
end
bits_in_factor = 0
local bits_in_factor_high = width + 1
while bits_in_factor_high - bits_in_factor > 1 do
local bits_in_new_factor = (bits_in_factor + bits_in_factor_high) / 2
bits_in_new_factor = bits_in_new_factor - bits_in_new_factor%1
if k % 2^bits_in_new_factor == 0 then
bits_in_factor = bits_in_new_factor
else
bits_in_factor_high = bits_in_new_factor
end
end
prev_k, prev_bits_in_factor = k, bits_in_factor
end
local factor, saved_bits, saved_bits_qty, pwr_saved_bits_qty = 2^bits_in_factor, 0, 0, 2^0
k = k / factor
width = width - bits_in_factor
local pwr_width = 2^width
local gap = pwr_width - k
repeat
modk = get_random_bits(width - saved_bits_qty) * pwr_saved_bits_qty + saved_bits
local modk_in_range = modk < k
if not modk_in_range then
local interval = gap
saved_bits = modk - k
saved_bits_qty = width - 1
pwr_saved_bits_qty = pwr_width / 2
repeat
saved_bits_qty = saved_bits_qty - 1
pwr_saved_bits_qty = pwr_saved_bits_qty / 2
if pwr_saved_bits_qty <= interval then
if saved_bits < pwr_saved_bits_qty then
interval = nil
else
interval = interval - pwr_saved_bits_qty
saved_bits = saved_bits - pwr_saved_bits_qty
end
end
until not interval
end
until modk_in_range
return m + modk * factor + get_random_bits(bits_in_factor)
else
return get_53_random_bits() / 2^53
end
end
local orig_Sleep = Sleep
function Sleep(x)
return orig_Sleep(x - x%1)
end
end

differential evolution global minimum problem

Im trying to get the global minimum of a non linear function with linear constraints. I share you the code:
rho = 1.0
g = 9.8
C = 1.0 #roughness coefficient
J = rho*g/(float(1e6)) #constant of function
capacity = [0.3875, 0.607, 0.374] #Supply data
demand = [0.768, 0.315, 0.38,] #Demand data
m= len(capacity)
n = len(demand)
x0 = np.array(m*n*[0.01]) #Initial point for algorithm
# In[59]:
#READ L AND d FROM ARCGIS !!!
L = (314376.57, 277097.9663, 253756.9869 ,265786.5632, 316712.6028, 232857.1468, 112063.9914, 135762.94, 131152.8206)
h= (75, 75, 75, 75, 75, 75, 1320,75,75)
K = np.zeros(m*n)
N=np.zeros(m*n)
# In[60]:
#Each path has its own L,d, therefore, own constant
# In[61]:
#np.seterr(all='ignore')
def diameter(x):
d = 1.484
if x >= 0.276:
d = 1.484
elif x >= 0.212:
d = 1.299
elif x >= 0.148:
d = 1.086
elif x >= 0.0975:
d = 0.881
elif x >= 0.079:
d = 0.793
elif x >= 0.062:
d = 0.705
elif x >= 0.049:
d = 0.626
elif x >= 0.038:
d = 0.555
elif x >= 0.030:
d = 0.494
elif x >= 0.024:
d = 0.441
elif x >= 0.0198:
d = 0.397
elif x >= 0.01565:
d = 0.353
elif x >= 0.0123:
d = 0.313
elif x >= 0.0097:
d = 0.278
elif x >= 0.0077:
d = 0.247
elif x >= 0.0061:
d = 0.22
elif x >= 0.0049:
d = 0.198
elif x >= 0.00389:
d = 0.176
elif x >= 0.0032:
d = 0.159
elif x >= 0.0025:
d = 0.141
elif x >= 0:
d = 0.123
return d
#Definition of Objetive function
def objective(x):
sum_obj = 0.0
for i in range(len(L)):
K = 10.674*L[i]/(C**1.852*diameter(x[i])**4.871)
N[i] = K*x[i]**2.852*J+x[i]*J*h[i]
sum_obj = sum_obj + N[i]
return sum_obj
print(str(objective(x0)))
#Definition of the constraints
GB=[]
for i in range(m):
GB.append(n*i*[0]+n*[1]+(m-1-i)*n*[0])
P=[]
for i in range(n):
P.append(m*(i*[0]+[1]+(n-1-i)*[0]))
DU=np.array(GB+P)
lb = np.array(m*[0] + demand) # Supply
ub = np.array(capacity + n*[np.inf]) # Demand
# In[62]:
b = (0, 1)
bnds = []
for i in range(m*n):
bnds.append(b)
cons = LinearConstraint(DU,lb,ub)
solution = differential_evolution(objective,x0,cons,bnds)
x = solution.x
# show initial objective
print('Initial SSE Objective: ' + str(objective(x0)))
# show final objective
print('Final SSE Objective: ' + str(objective(x)))
# print solution
print('Solution Supply to Demand:')
print('Q = ' + str(((np.around(x,6)).reshape(10,18))))
I dont know why, but when I run appear the following:
"if strategy in self._binomial:
TypeError: unhashable type: 'list'
Anyone have gotten the same mistake ? Its my first time trying to solve optimization problem, so I need a little bit of help. Any advice is welcome !!
Thanks a lot !
You're not calling differential_evolution correctly. For your example you should call it as:
differential_evolution(objective, bnds, contraints=(cons,))
(I'm not sure if there are additional problems)

how do you take a decimal to a fraction in lua with no added libraries?

i am working on a calculator running in pure lua but i need help with making the out put decimals in to fractions
This solution uses continued fraction to exactly restore fractions with denominator up to 107
local function to_frac(num)
local W = math.floor(num)
local F = num - W
local pn, n, N = 0, 1
local pd, d, D = 1, 0
local x, err, q, Q
repeat
x = x and 1 / (x - q) or F
q, Q = math.floor(x), math.floor(x + 0.5)
pn, n, N = n, q*n + pn, Q*n + pn
pd, d, D = d, q*d + pd, Q*d + pd
err = F - N/D
until math.abs(err) < 1e-15
return N + D*W, D, err
end
local function print_frac(numer,denom)
print(string.format("%.14g/%d = %d/%d + %g", numer, denom, to_frac(numer/denom)))
end
print_frac(1, 4) --> 1/4 = 1/4 + 0
print_frac(12, 8) --> 12/8 = 3/2 + 0
print_frac(4, 2) --> 4/2 = 2/1 + 0
print_frac(16, 11) --> 16/11 = 16/11 + 5.55112e-17
print_frac(1, 13) --> 1/13 = 1/13 + 0
print_frac(math.sqrt(3), 1) --> 1.7320508075689/1 = 50843527/29354524 + -4.44089e-16
print_frac(math.pi, 1) --> 3.1415926535898/1 = 80143857/25510582 + 4.44089e-16
print_frac(0, 3) --> 0/3 = 0/1 + 0
print_frac(-10, 3) --> -10/3 = -10/3 + -1.11022e-16
This is not possible. You need a class which stores fractions for that.
You can achieve an approximate solution. It works nicely for things that can be expressed as fraction and blows up for everything else
local function gcd(a, b)
while a ~= 0 do
a, b = b%a, a;
end
return b;
end
local function round(a)
return math.floor(a+.5)
end
function to_frac(num)
local integer = math.floor(num)
local decimal = num - integer
if decimal == 0 then
return num, 1.0, 0.0
end
local prec = 1000000000
local gcd_ = gcd(round(decimal*prec), prec)
local numer = math.floor((integer*prec + round(decimal*prec))/gcd_)
local denom = math.floor(prec/gcd_)
local err = numer/denom - num
return numer, denom, err
end
function print_frac(numer,denom)
print(string.format("%d/%d = %d/%d + %g", numer, denom, to_frac(numer/denom)))
end
print_frac(1,4)
print_frac(12,8)
print_frac(4,2)
print_frac(16,11)
print_frac(1,13)
Output:
1/4 = 1/4 + 0
12/8 = 3/2 + 0
4/2 = 2/1 + 0
16/11 = 290909091/200000000 + 4.54546e-10
1/13 = 76923077/1000000000 + 7.69231e-11

Questions about using Z3Py online to solve problems in Transport Phenomena

Certain problem in transport Phenomena is solved using the following code:
T_max, T_0, S, R, k, I, k_e, L, R, E, a = Reals('T_max T_0 S R k I k_e L R E a')
k = a*k_e*T_0
I = k_e*E/L
S = (I**2)/k_e
eq = T_0 + S* R**2/(4*k)
print eq
equations = [
T_max == eq,
]
print "Temperature equations:"
print equations
problem = [
R == 2, L == 5000,
T_0 == 20 + 273,
T_max == 30 + 273, k_e == 1,
a == 2.23*10**(-8), E > 0
]
print "Problem:"
print problem
print "Solution:"
solve(equations + problem)
using this code online we obtain
This output gives the correct answer but there are two issues in the code: a) the expresion named "eq" is not fully simplified and then it is necessary to give an arbitrary value for k_e . My question is: How to simplify the expression "eq" in such way that k_e be eliminated from "eq"?
Other example: To determine the radius of a tube
Code:
def inte(n,a,b):
return (b**(n+1))/(n+1)-(a**(n+1))/(n+1)
P_0, P_1, L, R, mu, q, C = Reals('P_0 P_1 L R mu q C')
k = (P_0 - P_1)/(2*mu*L)
equations = [0 == -k*inte(1,0,R) +C,
q == 2*3.1416*(-(k/2)*inte(3,0,R) + C*inte(1,0,R))]
print "Fluid equations:"
print equations
problem = [
L == 50.02/100, mu == (4.03*10**(-5)),
P_0 == 4.829*10**5, P_1==0,
q == 2.997*10**(-3), R >0
]
print "Problem:"
print problem
print "Solution:"
solve(equations + problem)
Output:
Fluid equations:
[-((P_0 - P_1)/(2·mu·L))·(R2/2 - 0) + C = 0, q =
3927/625·
(-(((P_0 - P_1)/(2·mu·L))/2)·(R4/4 - 0) + C·(R2/2 - 0))]
Problem:
[L = 2501/5000, mu = 403/10000000, P_0 = 482900, P_1 = 0, q = 2997/1000000, R > 0]
Solution:
[R = 0.0007512843?,
q = 2997/1000000,
P_1 = 0,
P_0 = 482900,
mu = 403/10000000,
L = 2501/5000,
C = 3380.3149444289?]

Resources