1

Here's a Z3 program, that creates two variables X and Y which cannot be equal, and have a domain of size 2:

var solver = ctx.MkSolver();

// Section A
var T = ctx.MkFiniteDomainSort("T", 2);
var a = ctx.MkNumeral(0, T);
var b = ctx.MkNumeral(1, T);
var x = ctx.MkConst("x", T);
var y = ctx.MkConst("y", T);

// Section B
//var a = ctx.MkInt(0);
//var b = ctx.MkInt(1);
//var x = ctx.MkIntConst("x");
//var y = ctx.MkIntConst("y");
//solver.Add(ctx.MkLe(a, x), ctx.MkLe(x, b));
//solver.Add(ctx.MkLe(a, y), ctx.MkLe(y, b));

// Section C
//solver.Assert(!ctx.MkEq(x, y));

// Section D
solver.Assert(ctx.MkImplies(ctx.MkEq(x, a), ctx.MkEq(y, b)));
solver.Assert(ctx.MkImplies(ctx.MkEq(x, b), ctx.MkEq(y, a)));
solver.Assert(ctx.MkImplies(ctx.MkEq(y, a), ctx.MkEq(x, b)));
solver.Assert(ctx.MkImplies(ctx.MkEq(y, b), ctx.MkEq(x, a)));

// Section E
//solver.Assert(ctx.MkEq(x, a));

var status = solver.Check();
Console.WriteLine(status);
Console.WriteLine(solver.Model);
Console.WriteLine(solver.Model.Eval(ctx.MkEq(x, a)));
Console.WriteLine(solver.Model.Eval(ctx.MkEq(y, b)));

// Should always be true, but doesn't work when only sections A and D are uncommented?
Console.WriteLine(solver.Model.Eval(ctx.MkImplies(ctx.MkEq(x, a), ctx.MkEq(y, b))));

I get output.

SATISFIABLE
(define-fun y () T
  0)
(define-fun x () T
  0)
true
false
false

This model clearly does not satisfy the constraints. I explicitly evaluate the 1st constraint to double check, and indeed, it's false.

The same problem does not occur if I use integers (section B instead of section A), or I add additional constraints (section C & E).

What am I missing? I'd like to use FiniteDomain as it's more convenient than adding bounds to integers, but it seems it behaves quite differently.

  • This looks bizarre indeed. Please report it at https://github.com/Z3Prover/z3/issues and update this question with what you find out! – alias Dec 01 '20 at 00:42
  • This could be explained if `ctx.MkNumeral` did actually not instantiate a value of sort `FiniteDomain` but, instead, of some other type. Some source code comments suggest using `Context.FromInt` to create a specific finite-domain value. – Patrick Trentin Dec 01 '20 at 10:26
  • 1
    Patrick: That was my original thought as well, but in those cases, z3 usually throws a sort-error. (I replicated the same using the Python interface, and it also behaves weirdly just like the OP posted.) I wonder if there's some underlying assumption that finite-domains are only to be used with the fixed-point engine (i.e., horn-clauses), but if that's the case z3 should still spit out a reasonable error message. Curious. – alias Dec 01 '20 at 16:28
  • @alias makes sense – Patrick Trentin Dec 01 '20 at 22:54
  • I've filed https://github.com/Z3Prover/z3/issues/4842. – BorisTheBrave Dec 02 '20 at 12:21

1 Answers1

0

This GitHub issue explains that FiniteDomain is only intended for the Datalog engine, and is broken in other uses.

Using enumerations is the correct way to do this in Z3 in other engines.