z3 timeout on nonlinear constraints - z3
I have a timeout problem when using z3 for nonlinear real arithmetics. The following code is to check if the 4-dimensional hyper-rectangle has a volume greater than 50000 and also satisfies some constraints. But the z3 cannot give an answer within 1 minute. How to make it faster?
a0min = Real('a0min')
a0max = Real('a0max')
a1min = Real('a1min')
a1max = Real('a1max')
a2min = Real('a2min')
a2max = Real('a2max')
a3min = Real('a3min')
a3max = Real('a3max')
volume = Real('volume')
s = Tactic('qfnra-nlsat').solver()
s.add(-a0min * (1.0 - a1max) + a2max * a3max <= -95000.0,
a0min > 0.0,
a0min < a0max,
a0max < 1000000.0,
a1min > 0.0,
a1min < a1max,
a1max < 1.0,
a2min > 1.0,
a2min < a2max,
a2max < 1000.0,
a3min > 1.0,
a3min < a3max,
a3max < 50.0,
(a0max - a0min) * (a1max - a1min) * (a2max - a2min) * (a3max - a3min) > 50000.0,
volume == (a0max - a0min) * (a1max - a1min) * (a2max - a2min) * (a3max - a3min))
print s.check()
And there is an interesting thing: if replacing some of the ">" and "<" with "<=" and ">=", the z3 solver can return the answer in two seconds. The corresponding code is as follows. Anyone knows why this happens?
a0min = Real('a0min')
a0max = Real('a0max')
a1min = Real('a1min')
a1max = Real('a1max')
a2min = Real('a2min')
a2max = Real('a2max')
a3min = Real('a3min')
a3max = Real('a3max')
volume = Real('volume')
s = Tactic('qfnra-nlsat').solver()
s.add(-a0min * (1.0 - a1max) + a2max * a3max <= -95000.0,
a0min >= 0.0,
a0min <= a0max,
a0max <= 1000000.0,
a1min >= 0.0,
a1min <= a1max,
a1max <= 1.0,
a2min >= 1.0,
a2min <= a2max,
a2max <= 1000.0,
a3min >= 1.0,
a3min <= a3max,
a3max <= 50.0,
(a0max - a0min) * (a1max - a1min) * (a2max - a2min) * (a3max - a3min) > 50000.0,
volume == (a0max - a0min) * (a1max - a1min) * (a2max - a2min) * (a3max - a3min))
print s.check()
In the first case, Z3 got "stuck" computing with real algebraic numbers. If we execute your script with
valgrind --tool=callgrind python nl.py
Interrupt after several minutes, and run
kcachegrind
We will see that Z3 is stuck inside algebraic_numbers::isolate_roots.
The current real algebraic number package used by the nlsat solver is very inefficient.
We have a new package for computing with algebraic numbers, but it is not integrated with nlsat yet.
One trick to avoid algebraic number computations is to use only strict inequalities. The equality volume == ... is harmless since it is eliminated during pre-processing time.
If we replace the first constraint with -a0min * (1.0 - a1max) + a2max * a3max < -95000.0, then Z3 also terminates quickly (also available online here).
a0min = Real('a0min')
a0max = Real('a0max')
a1min = Real('a1min')
a1max = Real('a1max')
a2min = Real('a2min')
a2max = Real('a2max')
a3min = Real('a3min')
a3max = Real('a3max')
volume = Real('volume')
s = Tactic('qfnra-nlsat').solver()
s.add(-a0min * (1.0 - a1max) + a2max * a3max < -95000.0,
a0min > 0.0,
a0min < a0max,
a0max < 1000000.0,
a1min > 0.0,
a1min < a1max,
a1max < 1.0,
a2min > 1.0,
a2min < a2max,
a2max < 1000.0,
a3min > 1.0,
a3min < a3max,
a3max < 50.0,
(a0max - a0min) * (a1max - a1min) * (a2max - a2min) * (a3max - a3min) > 50000.0,
volume == (a0max - a0min) * (a1max - a1min) * (a2max - a2min) * (a3max - a3min))
print s.check()
print s.model()
BTW, when you replace everything with <=, nlsat still has to use real algebraic computations, but the change influences the nlsat search-tree, and it manages to find the solution before it gets stuck in a real algebraic number computation.
Here are the three places where nlsat gets "stuck" in the examples we tried/examined
Real algebraic number computations (like your example). This will be fixed when we replace the current package with the new one.
Polynomial factorization. The current algorithm implemented in Z3 is very inefficient. This can also be fixed.
Subresultant computations. This one is tricky since as far as I know Z3 uses a very efficient implementation. The performance is similar to the implementation in state-of-the-art systems like Mathematica. This operation is used when Z3 is backtracking the search. The nice property is that we can prove that Z3 will always terminate using this approach. One alternative is to consider approximate methods that do not guarantee termination but are cheaper. Unfortunately, this is not a minor change like the previous two.
Related
Pinching image on edges as a custom CIWarpKernel does not produces results as expected
I have developed a custom CIWarpKernel which is the transposition of my Numbers model design as follows: The cell for positive y is: SIN($A2×PI()÷2)×(−COS(B$1×PI())×($A2+1)÷$W$3+SIN($A2 ×PI()÷2)) where $A2 is y, B$1 is x and $W$3 is the center stretching factor. The code is as follows: kernel vec2 panoramaDistortion (vec2 center) { float pi = 3.141592653589793; vec2 t = destCoord(); float x = t.x / center.x - 1.0; // x ∈ -1...1 float y = t.y / center.y - 1.0; // y ∈ -1...1 float rx = x; float delta = 50.0; float siny = sin(y * pi / 2.0); // See my model in Numbers: Aladdin PanoramPinch CIKernel file where $a2 = x and b$1 = y // sin($a2×pi()÷2)×(−cos(b$1×pi())×($a2+1)÷$w$3+sin($a2 ×pi()÷$w$5)) // sin(y×pi()÷2)×(−cos(x×pi())×(y+1)÷$w$3+sin(y×pi()÷2)) // sin($a22×pi()÷2)×(−cos(b$1×pi())×abs(1−$a22)÷$w$3−sin($a22 ×pi()÷$w$5)) float ry = y >= 0.0 ? siny * (-cos(x * pi) * (y + 1.0) / delta + siny) : siny * (-cos(x * pi) * (1.0 - y) / delta - siny) ; return vec2(center.x * (rx + 1.0), center.y * (ry + 1.0)); } The issue I have is that, though the transposition is 100% exact, I don't get the same result I have in my model. See the resulting warping of tiled-image: How it comes I have the dilatation at the center y=0 and at the upper- and bottom- sides? For information, my tiled-image is as follows:
Opencv naive image match
I'm using OpenCV/EmguCV to perform a naive matching procedure. I've two images, img1 and img2, and I enumerate the translations and rotations of img1, and match against img2 to find the optimal matched difference. Here's the code for (int dx = -img2.Width / 2; dx <= img1.Width - img2.Width / 2; dx++) for (int dy = -img2.Height / 2; dy <= img1.Height - img2.Height / 2; dy++) for (float r = 0; r < 2 * Math.PI; r += 0.1f) { var img2r = img2.Rotate(r, new Gray(0)); img1.ROI = new Rectangle(Math.Max(0, dx), Math.Max(0, dy), (Math.Min(dx + img2r.Width, img1.Width) - Math.Max(dx, 0)), (Math.Min(dy + img2r.Height, img2.Height) - Math.Max(dy, 0)) ); img2.ROI = new Rectangle(Math.Max(0, -dx), Math.Max(0, -dy), (Math.Min(dx + img2r.Width, img1.Width) - Math.Max(dx, 0)), (Math.Min(dy + img2r.Height, img2.Height) - Math.Max(dy, 0)) ); var diff = img1.AbsDiff(img2); var avg = diff.GetAverage(); img1.ROI = new Rectangle(); img2.ROI = new Rectangle(); } So my questions are 1) Do we have a built-in function to do this, For efficiency concerns? 2) How to perform a "sub-pixel" level of this matching? 3) Can we harness fft to accelerate the match to O(nlogn) by converting into frequency domain? Note cvMatchShape() won't make it because I'm doing naive matching. The two images are quite similar.
Orientation of non symmetrical a shape in Emgu or OpenCv
I'm trying to obtain the orientation of a shape (binary or contour). The shape is mostly rectangular but has a large hole on one side. I want my orientation to be consistent with this assymetry in the object. I've been looking at several articles that use the spatial and central moments for this. E.g. Binary Image Orientation but it seems that the orientation I get with this is sometimes off with a multiple of 90 degrees. The following document states that there is some ambiguity: http://public.cranfield.ac.uk/c5354/teaching/dip/opencv/SimpleImageAnalysisbyMoments.pdf If I implement this using private void GetCenterAndOrientationViaMoments(Contour<Point> cont, Size imageSize) { // obtain the orientation of the found object // first draw the binary blob in a separate image // I do this for the hole(s) in the image, but I'm not sure if it is needed. // Possibly I can tak the moments directly from the contour Image<Gray, byte> instanceImage = new Image<Gray, byte>(imageSize); instanceImage.FillConvexPoly(cont.ToArray(), new Gray(255)); for (Contour<Point> hole = cont.VNext; hole != null; hole = hole.HNext) instanceImage.FillConvexPoly(hole.ToArray(), new Gray(0)); // calculate the moments MCvMoments m = instanceImage.GetMoments(true); // MCvMoments m = cont.GetMoments(); double m00 = m.GetSpatialMoment(0, 0); double m10 = m.GetSpatialMoment(1, 0); double m01 = m.GetSpatialMoment(0, 1); double mu11 = m.GetCentralMoment(1, 1); double mu20 = m.GetCentralMoment(2, 0); double mu02 = m.GetCentralMoment(0, 2); // calculate the center PointF center = new PointF((float)(m10 / m00), (float)(m01 / m00)); // calculate the orientation // http://public.cranfield.ac.uk/c5354/teaching/dip/opencv/SimpleImageAnalysisbyMoments.pdf double theta = 0; double mu20_mu02 = (mu20 - mu02); if ((mu20_mu02 == 0) & (mu11 == 0)) theta = 0; else if ((mu20_mu02 == 0) & (mu11 > 0)) theta = Math.PI / 4; else if ((mu20_mu02 == 0) & (mu11 < 0)) theta = -Math.PI / 4; else if ((mu20_mu02 > 0) & (mu11 == 0)) theta = 0; else if ((mu20_mu02 < 0) & (mu11 == 0)) theta = -Math.PI / 2; else if ((mu20_mu02 > 0) & (mu11 > 0)) theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02); else if ((mu20_mu02 > 0) & (mu11 < 0)) theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02); else if ((mu20_mu02 < 0) & (mu11 > 0)) theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02) + Math.PI / 2; else if ((mu20_mu02 < 0) & (mu11 < 0)) theta = 0.5 * Math.Atan((2 * mu11) / mu20_mu02) - Math.PI / 2; #if DEBUG int radius = 25; instanceImage.Draw(new CircleF(center, radius), new Gray(100), 2); instanceImage.Draw( new LineSegment2DF( center, new PointF( (float)(center.X + radius * Math.Cos(theta)), (float)(center.Y + radius * Math.Sin(theta)))), new Gray(100), 2); ImageViewer.Show(instanceImage, string.Format("Center and orientation")); #endif } My orientation is correct, but does not always point to the same end of the object. In other words, I'm sometimes of by 180 degrees. I'm guessing the method cannot provide exactly what I want because it uses the covariance of the distribution (http://en.wikipedia.org/wiki/Image_moments#Examples_2) which gives does not take into account the assymmetry caused by the hole, am I right? Is there a way to resolve the 180 degrees ambiguity? Regards, Tom
Fast bilinear interpolation on old iOS devices
I've got the following code to do a biliner interpolation from a matrix of 2D vectors, each cell has x and y values of the vector, and the function receives k and l indices telling the bottom-left nearest position in the matrix // p[1] returns the interpolated values // fieldLinePointsVerts the raw data array of fieldNumHorizontalPoints x fieldNumVerticalPoints // only fieldNumHorizontalPoints matters to determine the index to access the raw data // k and l horizontal and vertical indices of the point just bellow p[0] in the raw data void interpolate( vertex2d* p, vertex2d* fieldLinePointsVerts, int fieldNumHorizontalPoints, int k, int l ) { int index = (l * fieldNumHorizontalPoints + k) * 2; vertex2d p11; p11.x = fieldLinePointsVerts[index].x; p11.y = fieldLinePointsVerts[index].y; vertex2d q11; q11.x = fieldLinePointsVerts[index+1].x; q11.y = fieldLinePointsVerts[index+1].y; index = (l * fieldNumHorizontalPoints + k + 1) * 2; vertex2d q21; q21.x = fieldLinePointsVerts[index+1].x; q21.y = fieldLinePointsVerts[index+1].y; index = ( (l + 1) * fieldNumHorizontalPoints + k) * 2; vertex2d q12; q12.x = fieldLinePointsVerts[index+1].x; q12.y = fieldLinePointsVerts[index+1].y; index = ( (l + 1) * fieldNumHorizontalPoints + k + 1 ) * 2; vertex2d p22; p22.x = fieldLinePointsVerts[index].x; p22.y = fieldLinePointsVerts[index].y; vertex2d q22; q22.x = fieldLinePointsVerts[index+1].x; q22.y = fieldLinePointsVerts[index+1].y; float fx = 1.0 / (p22.x - p11.x); float fx1 = (p22.x - p[0].x) * fx; float fx2 = (p[0].x - p11.x) * fx; vertex2d r1; r1.x = fx1 * q11.x + fx2 * q21.x; r1.y = fx1 * q11.y + fx2 * q21.y; vertex2d r2; r2.x = fx1 * q12.x + fx2 * q22.x; r2.y = fx1 * q12.y + fx2 * q22.y; float fy = 1.0 / (p22.y - p11.y); float fy1 = (p22.y - p[0].y) * fy; float fy2 = (p[0].y - p11.y) * fy; p[1].x = fy1 * r1.x + fy2 * r2.x; p[1].y = fy1 * r1.y + fy2 * r2.y; } Currently this code needs to be run every single frame in old iOS devices, say devices with arm6 processors I've taken the numeric sub-indices from the wikipedia's equations http://en.wikipedia.org/wiki/Bilinear_interpolation I'd accreciate any comments on optimization for performance, even plain asm code
This code should not be causing your slowdown if it's only run once per frame. However, if it's run multiple times per frame, it easily could be. I'd run your app with a profiler to see where the true performance problem lies. There is some room for optimization here: a) Certain index calculations could be factored out and re-used in subsequent calculations), b) You could dereference your fieldLinePointsVerts array to a pointer once and re-use that, instead of indexing it twice per index... but in general those things won't help a great deal, unless this function is being called many, many times per frame. In which case every little thing will help.
Lua for loop help!
I have the following code tile_width = 64; tile_height = 64; tile_map = { {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,3,1,1,1,1,1,1}, {1,1,1,1,1,3,1,1,1,1,1,1}, {1,1,1,1,1,3,1,1,1,1,1,1}, {1,1,1,1,1,3,1,1,1,1,1,1}, {1,1,1,1,1,1,2,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,2,1,1,1,1,1} } i=1; j=1; while i<table.getn(tile_map) do while j<table.getn(tile_map[i]) do print(tile_map[i][j]); x = (j * tile_width / 2) + (i * tile_width / 2) y = (i * tile_height / 2) - (j * tile_height / 2) print(x); print(y); j = j+1; end i = i+1; end And it works, but it only displays the first row values, and doesn't go onto the second row, third row, etc. What I am trying to do in another language for (i = 0; i < tile_map.size; i++): for (j = 0; j < tile_map[i].size j++): draw( tile_map[i][j], x = (j * tile_width / 2) + (i * tile_width / 2) y = (i * tile_height / 2) - (j * tile_height / 2) ) Any idea what I am doing wrong? Thanks!
Here is a cleaned up version of your code. Note changes: Use local variables instead of global. Use # for table size instead of table.getn(). Use numeric for loop instead of while. Lack of semicolons. If you'll uncomment io.write() calls and comment out prints, you will get your map printed out in a readable way. local tile_width = 64 local tile_height = 64 local tile_map = { {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,3,1,1,1,1,1,1}, {1,1,1,1,1,3,1,1,1,1,1,1}, {1,1,1,1,1,3,1,1,1,1,1,1}, {1,1,1,1,1,3,1,1,1,1,1,1}, {1,1,1,1,1,1,2,1,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1,1}, {1,1,1,1,1,1,2,1,1,1,1,1} } for i = 1, #tile_map do local row = tile_map[i] for j = 1, #row do --io.write(row[j]) print(row[j]) local x = (j * tile_width / 2) + (i * tile_width / 2) local y = (i * tile_height / 2) - (j * tile_height / 2) print(x) print(y) end --io.write("\n") end P.S. Make sure you've read the Programming in Lua 2nd Edition book. Note that the version, available online, is the first edition and it describes older Lua 5.0.
You have to reset j to 1 after each of the inner loops. Because: After the inner loop has been completed for the first time, j will have been incremented 64 times. But you want to start over with j set to 1. In the code of the other programming language, note that this re-setting of j is taken care of.