I am new to Z3, so excuse me if the question sounds too easy. I have two questions regrading constants in Z3 Java API.
How does creation of constants happen internally? To understand that I started by tracking
public BitVecExpr mkBVConst(String, int) down to public StringSymbol mkSymbol(String) which eventually calls Native.mkStringSymbol(var1.nCtx(), var2) which generates the variable in var3 in this line long var3 = INTERNALmkStringSymbol(var0, var2);
now because `INTERNALmkStringSymbol' is native I can't see its source. I am wondering about how does it operate. Does anyone know how does it work? Where to view its source?
Another thing I am confused about is the scoping of constants using the API. In the interactive Z3, it is maintained through matching push and pop but through the API, I am not sure how scoping is defined and managed.
Any insights or guidance is much appreciated.!
Z3 is open source, you can view and download the source from https://github.com/z3prover/z3.git. Symbols in Z3 are defined in src/util/symbol.h. You will see that symbols are similar to LISP atoms: they persist through the lifetime of the dll and are unique. So two symbols with the same name will be pointer-equal. The Java API calls into the C API, which is declared in src/api/z3_api.h. The directory src/api contains the API functions, including those that create symbols. When you create an expression constant, such as mkBVConst, it is an expression that is also pointer-unique (if you create the same mkBVConst twice, the unmanaged pointers will be equal. The Java pointers are not the same, but equality testing exploits all of this).
The Solver object has push and pop methods. You can add constraints to the solver object. The life-time of constraints follow the push/pop nesting: a constraint is active until there is a pop that removes the scope where the constraint was added.
Related
I'm using the Z3_parse_smtlib2_string function from the Z3 C API (via Haskell's Z3 lib) to parse an SMTLIB file and apply some tactics to simplify its content, however I notice that any push, pop and check-sat commands appear to be swallowed by this function and do not appear in the resulting AST.
Is there anyway that I can parse this without losing these commands (and then apply the required tactics, once again without losing them)?
I don't think it's possible to do this with Z3_parse_smtlib2_string. As you can see in the documentation "It returns a formula comprising of the conjunction of assertions in the scope (up to push/pop) at the end of the string." See: https://z3prover.github.io/api/html/group__capi.html#ga7905ebec9289b9fe5debcad965f6267e
Note that the reason for this is not just mere "not-implemented" or "buggy." Look at the return type of the function you're using. It returns a Z3_ast_vector, and Z3_ast only captures "expressions" in the SMTLib language. But push/pop etc. are not considered expressions by Z3, but rather commands; i.e., they are internally represented differently. (Whether this was a conscious choice or historical is something I'm not sure about.)
I don't think there's a function to do what you're asking; i.e., can return both expressions and commands. You can ask at https://github.com/Z3Prover/z3/discussions to see if the developers can provide an alternative API, or if they already have something exposed to the users that achieves this.
I've seen some Rust codebases use the #[repr(C)] macro (is that what it's called?), however, I couldn't find much information about it but that it sets the type layout in memory to the same layout as 'C's.
Here's what I would like to know: is this a preprocessor directive restricted to the compiler and not the language itself (even though there aren't any other compiler front-ends for Rust), and why does Rust even have a memory layout different than that of Cs? (it's just that I've never had to do this in another language).
Here's a nice situation to demonstrate what I meant: if someone creates another compiler for Rust, are they required to implement this macro, or is it a compiler specific thing?
#[repr(C)] is not a preprocessor directive, since Rust doesn't use a preprocessor 1. It is an attribute. Rust doesn't have a complete specification, but the repr attribute is mentioned in the Rust reference, so it is absolutely a part of the language. Implementation-wise, attributes are parsed the same way all other Rust code is, and are stored in the same AST. Rust has no "attribute pass": attributes are an actual part of the language. If someone else were to implement a Rust compiler, they would need to implement #[repr(C)].
Furthermore, #[repr(C)] can't be implemented without some compiler magic. In the absence of a #[repr(...)], Rust compilers are free to arrange the fields of a struct/enum however they want to (and they do take advantage of this for optimization purposes!).
Rust does have a good reason for using it's own memory layout. If compilers aren't tied to how a struct is written in the source code, they can do optimisations like not storing struct fields that are never read from, reordering fields for better performance, enum tag pooling2, and using spare bits throughout NonZero*s in the struct to store data (the last one isn't happening yet, but might in the future). But the main reason is that Rust has things that just don't make sense in C. For instance, Rust has zero-sized types (like () and [i8; 0]) which can't exist in C, trait vtables, enums with fields, generic types, all of which cause problems when trying to translate them to C.
1 Okay, you could use the C preprocessor with Rust if you really wanted to. Please don't.
2 For example, enum Food { Apple, Pizza(Topping) } enum Topping { Pineapple, Mushroom, Garlic } can be stored in just 1 byte since there are only 4 possible Food values that can be created.
What is this?
It is not a macro it is an attribute.
The book has a good chapter on what macros are and it mentions that there are "Attribute-like macros":
The term macro refers to a family of features in Rust: declarative macros with macro_rules! and three kinds of procedural macros:
Custom #[derive] macros that specify code added with the derive attribute used on structs and enums
Attribute-like macros that define custom attributes usable on any item
Function-like macros that look like function calls but operate on the tokens specified as their argument
Attribute-like macros are what you could use like attributes. For example:
#[route(GET, "/")]
fn index() {}
It does look like the repr attribute doesn't it 😃
So what is an attribute then?
Luckily Rust has great resources like rust-by-example which includes:
An attribute is metadata applied to some module, crate or item. This metadata can be used to/for:
conditional compilation of code
set crate name, version and type (binary or library)
disable lints (warnings)
enable compiler features (macros, glob imports, etc.)
link to a foreign library
mark functions as unit tests
mark functions that will be part of a benchmark
The rust reference is also something you usually look at when you need to know something more in depth. (chapter for attributes)
To the compiler authors out there:
If you were to write a rust compiler, and wanted to support things like the standard library or other crates then you would 100% need to implement these. Because the libraries use these and need them.
Otherwise I guess you could come up with a subset of rust that your compiler supports. But then most people wouldn't use it..
Why does rust not just use the C layout?
The nomicon explains why rust needs to be able to reorder fields of structs for example. For reasons of saving space and being more efficient. It is related to, among other things, generics and monomorphization. In repr(C) fields of structs must be in the same order as the definition.
The C representation is designed for dual purposes. One purpose is for creating types that are interoperable with the C Language. The second purpose is to create types that you can soundly perform operations on that rely on data layout such as reinterpreting values as a different type.
I am new to Z3.
I define a bool type variable a:
Z3_sort bool_type = Z3_mk_bool_sort(ctx);
Z3_ast a = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "a"), bool_type);
My question is how can I assign different value to a, seems I cannot assign Z3_L_TRUE to it directly.
Any suggestions? Thanks!
My first suggestion is to use the C++ API instead of the C API.
Using the C API is quite error prone. The distribution comes with examples of using both the C and the C++ API:
https://github.com/Z3Prover/z3/blob/master/examples/c/test_capi.c
and
https://github.com/Z3Prover/z3/blob/master/examples/c++/example.cpp
You will there see examples of creating logical variables, like you are doing,
and adding assertions that constrain logical variables.
It is easier to understand logical modeling using the text based API.
That is, I suggest you use the SMT-LIB format to model what you intend,
and this gives you a way to extrapolate what to do with the programmatic APIs.
Regarding your question: there is no notion of "assignment" in logical modeling.
You can assert equalities for sure. Furthermore Z3_L_TRUE is a return code used
when you check satisfiability. You can create a logical constant "true" using the method Z3_mk_true.
I was looking at the source code for the Append function in the SeqModule and noticed that there are a ton of duplicate methods with #xxx postfixed to them. Does anyone know why these are here?
In short, those are the concrete classes that back various local function values, and the #xxx values indicate the source code line number that caused them to be generated (though this is an implementation detail, and the classes could be given any arbitrary name).
Likewise, the C# compiler uses a conceptually similar scheme when defining classes to implement anonymous delegates, iterator state machines, etc. (see Eric Lippert's answer here for how the "magic names" in C# work).
These schemes are necessary because not every language feature maps perfectly to things that can be expressed cleanly in the CLR.
I am using Z3 from the API and I'm looking for a way to debug my constraints. My code compiles and Z3 runs on my constraints, but something is wrong with my constraints. I'm hoping to look at the constraints that I gave to Z3 to determine what is wrong or missing, but I'm not sure how to do this in a way that is very readable. The problem is that using facilities like SMTLIB_DUMP_ASSERTIONS does not provide meaningful names in any let bound variables. Since I have many reuses of the same expressions, nearly everything is let-bound with a generated variable.
Is there any way to dump a file of the input constraints, where let-bound variables have a name that I have assigned? I don't particularly care what the format is, but SMTLIB 1 or 2 would be nice.
No, you cannot provide names to let variables automatically created by Z3 AST printers.
One possible solution is to write your own AST printer. In the Z3 distribution, we have an example application examples/c/test_capi.c. It contains the function:
void display_ast(Z3_context c, FILE * out, Z3_ast v)
It shows how to implement a simple AST printer. This example is very simple, but it is a starting point.