z3 giving a surprising answer - python

I tried this:
import z3
n,x,y,z = z3.Ints('n x y z')
s = z3.Solver()
s.add(4/n==1/x+1/y+1/z)
s.add(x>0)
s.add(n>0)
s.add(y>0)
s.add(z>0)
s.check()
s.model()
and I get:
[x = 1, n = 2, z = 3, y = 1, div0 = [(1, 1) → 1, (4, 2) → 2, else → 0], mod0 = [(1, 3) → 1, else → 0]]
But 4/2 does not equal 1/1+1/1+1/3.
What am I doing wrong?

You've declared n, x, y, z as integers. So division is done as an integer, giving you 1/1 = 1 and 1/3 = 0; hence satisfying the equality 2=2.
The obvious thing to do is to use Real values for this problem.
Changing the declaration to:
n,x,y,z = z3.Reals('n x y z')
produces:
[z = 1, y = 1, n = 4/3, x = 1]
which does satisfy the equation you posed trivially.
In case you actually do want n, x, y, z to be integers; then you should convert them to reals before you divide, like this:
import z3
n,x,y,z = z3.Ints('n x y z')
s = z3.Solver()
s.add(4/z3.ToReal(n)==1/z3.ToReal(x)+1/z3.ToReal(y)+1/z3.ToReal(z))
s.add(x>0)
s.add(n>0)
s.add(y>0)
s.add(z>0)
print(s.check())
print(s.model())
This prints:
sat
[n = 4, x = 3, z = 3, y = 3]
again satisfying your constraints.

Related

What is wrong in my code using DHT to compute convolution?

The Discrete Hartley Transform can be computed as
import numpy as np
def dht(x:np.array):
X = np.fft.fft(x)
X = np.real(X) - np.imag(X)
return X
def idht(X:np.array):
n = len(X)
X = dht(X)
x = 1/n * X
return x
Circular convolution can be computed using the DHT according to a theorem illustrated here, here(eq.4.7.22-4.7.25) and in many other places. I implemented the corresponding algorithm and compared it with circular convolution compute using the FFT, but the results are not even close. Why?
def conv(x:np.array, y:np.array):
X = dht(x)
Y = dht(y)
Xflip = np.flip(X)
Yflip = np.flip(Y)
Yplus = Y + Yflip
Yminus = Y - Yflip
Z = 0.5 * (X * Yplus + Xflip * Yminus)
z = idht(Z)
return z
def test_conv():
x = np.ones((5, ))
y = np.copy(x)
z = conv(x, y)
z1 = np.real(np.fft.ifft(np.fft.fft(x)*np.fft.fft(y)))
np.testing.assert_allclose(z, z1, err_msg="test_convolution() failed")
if (__name__=='__main__'):
test_conv()
print("test_conv passed")
Output:
Traceback (most recent call last):
File "ronf.py", line 35, in <module>
test_conv()
File "ronf.py", line 31, in test_conv
np.testing.assert_allclose(z, z1, err_msg="test_convolution() failed")
File "/home/andrea/vscode_venv/lib/python3.8/site-packages/numpy/testing/_private/utils.py", line 1528, in assert_allclose
assert_array_compare(compare, actual, desired, err_msg=str(err_msg),
File "/home/andrea/vscode_venv/lib/python3.8/site-packages/numpy/testing/_private/utils.py", line 842, in assert_array_compare
raise AssertionError(msg)
AssertionError:
Not equal to tolerance rtol=1e-07, atol=0
test_convolution() failed
Mismatched elements: 5 / 5 (100%)
Max absolute difference: 5.65018378
Max relative difference: 1.13003676
x: array([ 0. , 4.105099, 5.992006, 3.053079, -0.650184])
y: array([5., 5., 5., 5., 5.])
The issue is about the flipping part. To show with an example:
For a given array X_k, we need X_{-k} i.e., X_{N-k}.
N := 5
X_k := [0, 1, 2, 3, 4]
np.flip does this:
[4, 3, 2, 1, 0]
However, this is not X_{N-k}! We need:
X_{N-k} = [0, 4, 3, 2, 1]
since:
for k = 0 => X[5-0] = X[0] = 0
for k = 1 => X[5-1] = X[4] = 4
... ...
for k = 4 => X[5-4] = X[1] = 1
That is, we assume periodicity of N s.t. X[0] = X[N] and so on, but np.flip's result doesn't obey that. In short, first element should stay as is, others should flip.
One way to fix is to np.roll after your flips to rotate it 1 position:
def conv(x:np.array, y:np.array):
X = dht(x)
Y = dht(y)
Xflip = np.roll(np.flip(X), shift=1) # change is here
Yflip = np.roll(np.flip(Y), shift=1) # and here only
Yplus = Y + Yflip
Yminus = Y - Yflip
Z = 0.5 * (X * Yplus + Xflip * Yminus)
z = idht(Z)
return z
Then I get:
>>> a = np.ones((5,))
>>> conv(a, a)
array([5., 5., 5., 5., 5.])

sympy collect undefined functions

I have an expression in sympy that is a linear combination of an evaluated function, f. Schematically
expr = Sum_{m,n} c_{m,n} f(x+a_m,y+a_n)
where c_{m,n} is a coefficient depending on the variables x,y. A very simple example is
import sympy as sp
x, y = sp.symbols("x, y")
f = sp.Function("f")(x,y)
expr = 0
for i in range(0,3):
expr += (x-i)* f.subs({x: x+2*i, y: y+3*i})
In my actual code expr is the result of a long succession of sums and the function g not simplify like here. Is there an efficient way of grouping functions with different argument together, like collect(expr) does for polynomials? What I am after is to obtain a structured list:
In: someFunction(...)
Out: [..., [c_{m,n}, x+a_m, y+a_n ], ...]
in the example above
In: someFunction(expr)
Out: [[x, x, y], [x - 1, x + 2, y + 3], [x - 2, x + 4, y + 6]]
I'm not sure if this does exactly what you want but you can use pattern matching:
In [27]: expr
Out[27]: x⋅f(x, y) + (x - 2)⋅f(x + 4, y + 6) + (x - 1)⋅f(x + 2, y + 3)
In [28]: a, b, c = symbols('a, b, c', cls=Wild)
In [29]: pattern = a*f(b, c)
In [30]: for term in Add.make_args(expr):
...: print(term.match(pattern))
...:
{b_: x, c_: y, a_: x}
{b_: x + 2, c_: y + 3, a_: x - 1}
{b_: x + 4, c_: y + 6, a_: x - 2}

Problem with np.vectorize function in Python

I have created this code as below:
def scalar_function(x, y):
if x <= y:
z = x*y
else:
z = x/y
return z
And
def vector_function(x, y):
vfunc = np.vectorize(scalar_function)
return vfunc
But when I try to put: vector_function([1, 2, 3, 4], 2), the output is <numpy.vectorize at 0x226a1d9aeb8> instead of resulting array of numbers.
Can anyone point out my mistake? Thanks.
You have return return vfunc which return Vectorized function That you got. you may want return vfunc(x,y)
>>> def vector_function(x, y):
vfunc = np.vectorize(scalar_function)
return vfunc(x, y)
>>> vector_function([1, 2, 3, 4], 2)
array([2, 4, 1, 2])
There is no need for np.vectorize:
x = np.asarray(x)
y = np.asarray(y)
np.where(x <= y, x*y, x/y)
does the same and is actually vectorized.

Interpolate polynomial over a finite field

I want to use python interpolate polynomial on points from a finite-field and get a polynomial with coefficients in that field.
Currently I'm trying to use SymPy and specifically interpolate (from sympy.polys.polyfuncs), but I don't know how to force the interpolation to happen in a specific gf. If not, can this be done with another module?
Edit: I'm interested in a Python implementation/library.
SymPy's interpolating_poly does not support polynomials over finite fields. But there are enough details under the hood of SymPy to put together a class for finite fields, and find the coefficients of Lagrange polynomial in a brutally direct fashion.
As usual, the elements of finite field GF(pn) are represented by polynomials of degree less than n, with coefficients in GF(p). Multiplication is done modulo a reducing polynomial of degree n, which is selected at the time of field construction. Inversion is done with extended Euclidean algorithm.
The polynomials are represented by lists of coefficients, highest degrees first. For example, the elements of GF(32) are:
[], [1], [2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]
The empty list represents 0.
Class GF, finite fields
Implements arithmetics as methods add, sub, mul, inv (multiplicative inverse). For convenience of testing interpolation includes eval_poly which evaluates a given polynomial with coefficients in GF(pn) at a point of GF(pn).
Note that the constructor is used as G(3, 2), not as G(9), - the prime and its power are supplied separately.
import itertools
from functools import reduce
from sympy import symbols, Dummy
from sympy.polys.domains import ZZ
from sympy.polys.galoistools import (gf_irreducible_p, gf_add, \
gf_sub, gf_mul, gf_rem, gf_gcdex)
from sympy.ntheory.primetest import isprime
class GF():
def __init__(self, p, n=1):
p, n = int(p), int(n)
if not isprime(p):
raise ValueError("p must be a prime number, not %s" % p)
if n <= 0:
raise ValueError("n must be a positive integer, not %s" % n)
self.p = p
self.n = n
if n == 1:
self.reducing = [1, 0]
else:
for c in itertools.product(range(p), repeat=n):
poly = (1, *c)
if gf_irreducible_p(poly, p, ZZ):
self.reducing = poly
break
def add(self, x, y):
return gf_add(x, y, self.p, ZZ)
def sub(self, x, y):
return gf_sub(x, y, self.p, ZZ)
def mul(self, x, y):
return gf_rem(gf_mul(x, y, self.p, ZZ), self.reducing, self.p, ZZ)
def inv(self, x):
s, t, h = gf_gcdex(x, self.reducing, self.p, ZZ)
return s
def eval_poly(self, poly, point):
val = []
for c in poly:
val = self.mul(val, point)
val = self.add(val, c)
return val
Class PolyRing, polynomials over a field
This one is simpler: it implements addition, subtraction, and multiplication of polynomials, referring to the ground field for operations on coefficients. There is a lot of list reversals [::-1] because of SymPy's convention to list monomials starting with highest powers.
class PolyRing():
def __init__(self, field):
self.K = field
def add(self, p, q):
s = [self.K.add(x, y) for x, y in \
itertools.zip_longest(p[::-1], q[::-1], fillvalue=[])]
return s[::-1]
def sub(self, p, q):
s = [self.K.sub(x, y) for x, y in \
itertools.zip_longest(p[::-1], q[::-1], fillvalue=[])]
return s[::-1]
def mul(self, p, q):
if len(p) < len(q):
p, q = q, p
s = [[]]
for j, c in enumerate(q):
s = self.add(s, [self.K.mul(b, c) for b in p] + \
[[]] * (len(q) - j - 1))
return s
Construction of interpolating polynomial.
The Lagrange polynomial is constructed for given x-values in list X and corresponding y-values in array Y. It is a linear combination of basis polynomials, one for each element of X. Each basis polynomial is obtained by multiplying (x-x_k) polynomials, represented as [[1], K.sub([], x_k)]. The denominator is a scalar, so it's even easier to compute.
def interp_poly(X, Y, K):
R = PolyRing(K)
poly = [[]]
for j, y in enumerate(Y):
Xe = X[:j] + X[j+1:]
numer = reduce(lambda p, q: R.mul(p, q), ([[1], K.sub([], x)] for x in Xe))
denom = reduce(lambda x, y: K.mul(x, y), (K.sub(X[j], x) for x in Xe))
poly = R.add(poly, R.mul(numer, [K.mul(y, K.inv(denom))]))
return poly
Example of usage:
K = GF(2, 4)
X = [[], [1], [1, 0, 1]] # 0, 1, a^2 + 1
Y = [[1, 0], [1, 0, 0], [1, 0, 0, 0]] # a, a^2, a^3
intpoly = interp_poly(X, Y, K)
pprint(intpoly)
pprint([K.eval_poly(intpoly, x) for x in X]) # same as Y
The pretty print is just to avoid some type-related decorations on the output. The polynomial is shown as [[1], [1, 1, 1], [1, 0]]. To help readability, I added a function to turn this in a more familiar form, with a symbol a being a generator of finite field, and x being the variable in the polynomial.
def readable(poly, a, x):
return Poly(sum((sum((c*a**j for j, c in enumerate(coef[::-1])), S.Zero) * x**k \
for k, coef in enumerate(poly[::-1])), S.Zero), x)
So we can do
a, x = symbols('a x')
print(readable(intpoly, a, x))
and get
Poly(x**2 + (a**2 + a + 1)*x + a, x, domain='ZZ[a]')
This algebraic object is not a polynomial over our field, this is just for the sake of readable output.
Sage
As an alternative, or just another safety check, one can use the lagrange_polynomial from Sage for the same data.
field = GF(16, 'a')
a = field.gen()
R = PolynomialRing(field, "x")
points = [(0, a), (1, a^2), (a^2+1, a^3)]
R.lagrange_polynomial(points)
Output: x^2 + (a^2 + a + 1)*x + a
I'm the author of the galois Python library. Polynomial interpolation can be performed with the lagrange_poly() function. Here's a simple example.
In [1]: import galois
In [2]: galois.__version__
Out[2]: '0.0.32'
In [3]: GF = galois.GF(3**5)
In [4]: x = GF.Random(10); x
Out[4]: GF([ 33, 58, 59, 21, 141, 133, 207, 182, 125, 162], order=3^5)
In [5]: y = GF.Random(10); y
Out[5]: GF([ 34, 239, 120, 170, 31, 165, 180, 79, 215, 215], order=3^5)
In [6]: f = galois.lagrange_poly(x, y); f
Out[6]: Poly(165x^9 + 96x^8 + 9x^7 + 111x^6 + 40x^5 + 208x^4 + 55x^3 + 17x^2 + 118x + 203, GF(3^5))
In [7]: f(x)
Out[7]: GF([ 34, 239, 120, 170, 31, 165, 180, 79, 215, 215], order=3^5)
The finite field element display may be changed to either the polynomial or power representation.
In [8]: GF.display("poly"); f(x)
Out[8]:
GF([ α^3 + 2α + 1, 2α^4 + 2α^3 + 2α^2 + α + 2,
α^4 + α^3 + α^2 + α, 2α^4 + 2α + 2,
α^3 + α + 1, 2α^4 + α,
2α^4 + 2α^2, 2α^3 + 2α^2 + 2α + 1,
2α^4 + α^3 + 2α^2 + 2α + 2, 2α^4 + α^3 + 2α^2 + 2α + 2], order=3^5)
In [9]: GF.display("power"); f(x)
Out[9]:
GF([α^198, α^162, α^116, α^100, α^214, α^137, α^169, α^95, α^175, α^175],
order=3^5)

Creating a Running Total column in a matrix?

Related to this question I recently posted & resolved.
If the 3rd column of a matrix is to be changed to be the running total of the sums, how would I adjust my code to do so?
This is where I'm at so far:
def dice(n):
rolls = np.empty(shape=(n, 3),dtype=int)
for i in range(n):
x = random.randint(1,6)
y = random.randint(1,6)
if x in [1,3,5] or y in [1,3,5]:
sum_2_dice = x + y
z = np.cumsum(sum_2_dice)
rolls[i,:] = x, y, z
else:
sum_2_dice = -(x+y) # meaning you "lose the sum" basically
z = np.cumsum(sum_2_dice)
rolls[i,:] = x, y, z
return rolls `
So for example: dice(2)
returns
array[[2, 6, -8],
[1, 3, 4],
[5, 2, 7])
when it should really be returning:
array[[2, 6, -8],
[1, 3, -4],
[5, 2, 3])
I thought np.cumsum would be doing something, but I'm not sure. Is a while loop needed to do this (I'm not sure of where it'd be applied)? I've tried various adjustments like instead of having z = np.cumsum(sum_2_dice) I did sum_2_dice += sum_2_dice (consequently the code that followed it was rolls[i,:] = x, y, sum_2_dice but that was terribly wrong since all that ended up doing was doubling the sum values in every column, not doing any sort of running total calculations.
For your purposes, an easy way to keep track of z would be to initialise it outside of the loop, then keep adding the value of sum_2_dice.
def dice(n):
z = 0
rolls = np.empty(shape=(n, 3),dtype=int)
for i in range(n):
x = random.randint(1,6)
y = random.randint(1,6)
if x in [1,3,5] or y in [1,3,5]:
sum_2_dice = x + y
z += sum_2_dice
rolls[i,:] = x, y, z
else:
sum_2_dice = -(x+y) # meaning you "lose the sum" basically
z += sum_2_dice
rolls[i,:] = x, y, z
return rolls
print (dice(3))
#[[ 6 2 -8]
# [ 4 5 1]
# [ 1 5 7]]
For reference, numpy.cumsum is normally used to get the cumulative sum of the elements of arrays, for example:
test = np.arange(0,5,1)
print (test)
# [0 1 2 3 4]
print (np.cumsum(test))
# [0 1 3 6 10]

Categories

Resources