Z3: Should I use Arrays, IntVectors, or something else? - z3

I am wondering what datatype I should be using for my z3 application. My understanding is that the only options for integer-array-like data structures are Array(IntSort(), IntSort()) and IntVector().
Reasons I think Arrays are overkill: Each array element is only written once, I'm not doing anything like Store((Store(X, y, z1)), y, z2). In addition, each array has a predefined length of <= 256 (and each integer in the array is between 0 and 63).
Reasons I think BitVectors won't work: I want to use Int variables to index into the arrays. For instance, I might have z = Int('z'), some clauses constraining z, and then Or(arr[z] == 2, arr[z + 1] == 2). My understanding after playing around with z3 and reading up is that vectors don't support this.
Is there a way I can get the power of variable-indexing without having to use expensive Array operations?

If you have small arrays of fixed-length with no symbolic index access, then I'd strongly recommend using an IntVector (See https://z3prover.github.io/api/html/namespacez3py.html#a7e166f891df8f17fd23290bec963b03c)
Note the important thing here is whether you need access with a symbolic index. (That is, do you always address your array with known constant indices, or do you need the ability to read/write to a symbolically addressed location.) From your description, it appears you always statically know the address, so IntVector is your best choice. If addresses can be symbolic, then you have to use good old SMTLib arrays, which are more costly.

Related

Nested fixed-size arrays/records

I want to model fixed-size arrays that can contain records and other fixed-size arrays. I then want to model store and select accesses to them.
I currently use ArraySorts for the arrays and Datatypes for the records. However, according to this answer (arrays) and this answer (records), these aren't really intended for my usecase. Is there anything else in Z3 I could use instead?
Background: I want to model pointers as they occur in the LLVM IR. For this, each pointer has a data array that represents the memory buffer into which it is pointing and an indices array that represents the indices used in getelementptr calls. Since the memory buffer could contain pointers or structs, I need to be able to nest the arrays (or store the records in arrays).
An example (in z3py) looks like this:
Vec3 = z3.Datatype("Vec3")
Vec3.declare("Vec3__init",
("x", z3.IntSort()),
("y", z3.IntSort()),
("z", z3.IntSort())
)
Vec3 = Vec3.create()
PointerVec3 = z3.Datatype("Pointer__Vec3")
PointerVec3.declare("Pointer__Vec3__init",
("data", z3.ArraySort(z3.BitVecSort(32), Vec3)),
("nindices", z3.IntSort()),
("indices", z3.ArraySort(z3.IntSort(), z3.BitVecSort(32)))
)
PointerVec3 = PointerVec3.create()
Arrays and records are the only way to model these things in z3/SMT-Lib. And they can be nested as you wish.
It is true that SMTLib arrays are not quite like arrays you find in regular programming languages. But it's not true that they are always unbounded. Their size exactly matches the cardinality of their domain. If you want a bounded array, I recommend using an appropriate BitVec type for your source. For an n-bit bit vector, your array will have 2^n elements. You can work with a small enough n, and treat that as your array; which typically matches what you see in practice: Most of such internal arrays will be a power-of-two anyhow. (Moreover, provers usually don't do well with large arrays; so sticking to a small power-of-two is a good idea, at least to start with.)
So, these are your only options. Stack-overflow works the best if you try it out and actually ask about what sort of problems you ran into.

How does dafny encode the validation of conditions involving arrays?

I'm evaluating the use Dafny, compared to the direct use of z3 for encoding a problem we have in my company.
While trying out the z3 API I noticed that there is an Array type, which seems to resemble a lot the way Z3 implements total functions. It seems like there is not an easy way to reason on the Lenght of such arrays in Z3.
If we look at Dafny, it can easily prove the following correct
method Find(a: array<int>) returns (index: int)
ensures index == a.Length
{
index := a.Length;
}
Now, for me the question is:
How is the array used by Dafny encoded in Z3?
Let's say that Dafny doesn't actually use Z3 arrays, where can I find some documentation on the way Dafny abstract things that do not identify a bounded number of variables in Z3 (such as array)? Same question applies for any object that is heap allocated, does it use allocation-site abstractions or something else?
There's really no magic, nor anything "implicit" that guarantees all array accesses are within bounds. You can surely write Dafny programs that index out-of-bounds, you just cannot prove useful things for them. Dafny makes you do this, by generating the necessary "in-bounds" check; but it's still up to you to have the proof go through by putting in the necessary annotations. Is that what you're looking for? This is also explained here: https://rise4fun.com/Dafny/tutorialcontent/guide#h27

Increasing the length of a tuple in Erlang

How can I increase the length of a tuple in Erlang? For example, suppose Tup={1,2,3}, and now I want to add another element to it. Is there any way to do this?
Tuple is not suppose to be a flexible data structure. If you are resizing it often, then you should consider using other erlang data structures like lists, maps or sets - depends on your expectation. Here is nice introduction to key-value stores.
But if you really have to extend that tuple, then you can use erlang:append_element/2:
{1,2,3,4} = erlang:append_element({1,2,3}, 4).
Tuples aren't mutable so you can't, strictly speaking, increase the length.
Generally, if you want a variable-number-of-things datatype, a tuple will be very inconvenient. For example, iterating over all elements of a list is highly idiomatic, while iterating over all elements of a tuple whose size is unknown at compile-time is a pain.
However, a common pattern is to get a tuple as a result from some function and return elements of that tuple plus additions.
country_coords(Name) ->
{Lat, Lng} = find_address(Name),
{_Street, _City, _Zip, Country} = geocode(Lat, Lng),
{ok, Lat, Lng, Country}.
erlang:append_element(tuple_whose_length_to_increase, element_to_be).This is the inbuilt function but tuples,lists are not meant to be flexible.So avoid using this function unless there is no other way

Dart int and double being interned? Treated specially by identical()?

Dart has both:
an equality operator == and
a top-level function named identical().
By the choice of syntax, it feels natural to want to use Dart's == operator more frequently than identical(), and I like that. In fact, the Section on Equality of the Idiomatic Dart states that "in practice, you will rarely need to use" identical().
In a recent answer to one of my questions concerning custom filters, it seems that Angular Dart favors use of identical() rather than == when trying to determine whether changes to a model have reached a steady state. (Which can make sense, I suppose, for large models for reasons of efficiency.)
This got me to thinking about identity of int's and so I wrote some tests of identical() over ints. While I expected that small ints might be "interned/cached" (e.g. similar to what is done by Java's Integer.valueOf()), to my surprise, I can't seem to generate two ints that are equal but not identical. I get similar results for double.
Are int and double values being interned/cached? Or maybe identical() is treating them specially? Coming from a Java background, I used to equate equate Dart's:
== to Java's equal() method and
identical() to Java's equality test ==.
But that now seems wrong. Anyone know what is going on?
Numbers are treated specially. If their bit-pattern is the same they must be identical (although it is still debated if this includes the different versions of NaNs).
The main reasons are expectations, leaking of internal details and efficiency.
Expectations: users expect numbers to be identical. It goes against common sense that x == y (for two integers) but not identical(x, y).
Leaking of internal details: the VM uses SMIs (SMall Integers) to represent integers in a specific range (31 bits on 32-bit machines, 63 on 64-bit machines). These are canonicalized and are always identical. Exposing this internal implementation detail would lead to inconsistent results depending on which platform you run.
Efficiency: the VM wants to unbox numbers wherever it can. For example, inside a method doubles are frequently moved into registers. However, keeping track of the original box can be cumbersome and difficult.
foo(x, y) {
var result = x;
while(y-- > 0) {
result += x;
}
return result;
}
Suppose, that the VM optimizes this function and moves result into a register (unboxing x in the process). This allows for a tight loop where result is then efficiently modified. The difficult case happens, when y is 0. The loop wouldn't execute and foo would return x directly. In other words, the following would need to be true:
var x = 5.0;
identical(x, foo(x, 0)); // should be true.
If the VM unboxed the result variable in the method foo it would need to allocate a fresh box for the result and the identical call would therefore return false.
By modifying the definition of identical all these problems are avoided. It comes with a small cost to the identical check, though.
Seems like I posted too quickly. I just stumbled on Dart Issue 13084: Spec says identical(1.0, 1) is true, even if they have different types which led me to the Dart section on Object Identity of the language spec. (I had previously search for equality in the spec but not object identity.)
Here is an excerpt:
The predefined dart function identical() is defined such that identical(c1, c2) iff:
- c1 evaluates to either null or an instance of
bool and c1 == c2, OR
- c1 and c2 are instances of int and c1 == c2, OR
- c1 and c2 are constant strings and c1 == c2, OR
- c1 and c2 are instances of double and one of the following holds: ...
and there are more clauses dealing with lists, maps and constant objects. See the language spec for the full details. Hence, identical() is much more than just a simple test for reference equality.
I can't remember the source for this, but somewhere on dartlang.org or the issue tracker it was said that num, int and double are indeed getting special treatment. One of those special treatments is that you can't subclass those types for performance reasons, but there may be more. What exactly this special treatment entails can probably only be answered by the developers, or maybe someone who knows the specification by heart, but one thing can be inferred:
The numeric types are dart objects - they have methods you can call on their instances. But they also have qualities of primitive data types, as you can do int i = 3;, while a pure object should have a new keyword somewhere. This is different from Java, where there are real primitive types and real objects wrapping them and exposing instance methods.
While the technical details certainly are more complex, if you think about dart numerics as a blend of object and primitive, your comparison to Java still makes sense. In Java, new Integer(5).equals(new Integer(5)) evaluates to true, and so does 5==5.
I am aware this is not a very technically correct answer, but I hope it's still useful to make sense of the behaviour of dart numerics when coming from a Java background.

F# how can I setup array length in type delcaration

I can do (x : int array)
But I need only 300 elements array , so how do I (x : int[300]) ?
Can't find such information over msdn )
#Marcelo Cantos No reason , but I always used sized arrays. Why not ?
No. The F# type system does not support types such as "array of size 300", and even if it did, using the type system to check potential array overflows at compile time is too impractical to implement.
Besides, "has exactly 300 elements" is an useless property in F# in almost all situations, because there is a wealth of functions and primitives that work on arrays of arbitrary size without any risk of overflow (map or iter, for instance). Why write code that works for 300 elements when you can just as easily write code that works for any number of elements ?
If you really need to represent the "has exactly 300 elements" property, the simplest thing you could do is create a wrapper type around the native array type. This lets you restrict those operations that return arrays to only operations that respect the 300-element invariant (such as a map from another 300-element array, or a create where the length property is always 300). I'm afraid this isn't as simple as you hoped, but since F# does not natively support 300-element arrays, you will need to describe all the function invariants yourself.

Resources