Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failure of existential introduction #2721

Open
jtristan opened this issue Sep 9, 2022 · 2 comments
Open

Failure of existential introduction #2721

jtristan opened this issue Sep 9, 2022 · 2 comments
Labels
incompleteness Things that Dafny should be able to prove, but can't

Comments

@jtristan
Copy link
Contributor

jtristan commented Sep 9, 2022

The following two examples give: Error: A postcondition might not hold on this return path.


	lemma example_failing_1(a: nat)
		ensures exists x: nat :: a == x
	{
		assert a == a;
	}
	lemma example_failing_2()
		ensures forall a: nat :: exists x: nat :: a == x
	{
		forall a: nat {
			assert a == a;
		}
	}	

Note for reference that the following does work:

	datatype Step =
		| Step(n: nat)

	lemma example_working(a: nat)
		ensures forall a: nat :: exists x: nat :: Step(a) == Step(x) 
	{
		assert Step(a) == Step(a); 
	}

Finally, a Coq reference:

Lemma test: forall a: nat, exists x: nat, a = x.
Proof.
  intro a.
  exists a. 
  reflexivity.
Qed.
@jtristan jtristan added the incompleteness Things that Dafny should be able to prove, but can't label Sep 9, 2022
@RustanLeino
Copy link
Collaborator

This issue has to do with how quantifiers are instantiated, see https://github.com/dafny-lang/dafny/wiki/FAQ#how-does-dafny-handle-quantifiers-ive-heard-about-triggers-what-are-those. (More precisely, how universal quantifiers are instantiated and how witnesses for existential quantifiers are found.) Essentially, the a == x expression does have a good matching pattern (aka "trigger"), whereas the expression Step(x) does.

There may be a way to change Dafny's verification-condition generation so that some of these examples would go through automatically. For example, Dafny already is able to verify

var x: nat :| a == x;

whose proof obligation is the same as the postcondition of example_failing_1. (Implementation note: To try this, incorporate some logic in TrSplitExpr in Translator.cs akin the analysis and logic involved in :|.)

There are workarounds to make the examples above verify. Each one involves either manually giving triggers or changing the expressions involved in such a way that Dafny can find triggers for them automatically. Manual triggers are to be used very sparingly, if at all, but they can be effective in examples like those above. Depending on your taste, you may have objections to either workaround. In the following, I will show solutions using both.

ghost function Id<X>(x: X): X { x }

lemma example_failing_1'(a: nat)
  ensures exists x: nat :: a == Id(x) // Dafny picks Id(x) as the matching pattern
{
  assert Id(a) == a; // this occurrence of Id(a) triggers the matching pattern
  assert a == a;
}
ghost predicate LookAtMe<X>(x: X) { true }

lemma example_failing_1''(a: nat)
  ensures exists x: nat {:trigger LookAtMe(x)} :: a == x
{
  assert LookAtMe(a);
  assert a == a;
}
ghost predicate Outer<X>(x: X) { true }
ghost predicate Inner<X>(x: X) { true }

lemma example_failing_2()
  ensures forall a: nat :: Outer(a) ==> exists x: nat :: Inner(x) && a == x
{
  forall a: nat | Outer(a)
    ensures exists x: nat :: Inner(x) && a == x
  {
    assert Inner(a);
    assert a == a;
  }
}

@MikaelMayer
Copy link
Member

MikaelMayer commented Mar 30, 2023

Also, you don't need to modify the inner part of the exists to prove it, you can also manually set up a trigger like this:

function Trigger<T>(t: T): T { t }

lemma example_failing_1(a: nat)
  ensures exists x: nat {:trigger Trigger(x)}:: a == x
{
  var _ := Trigger(a);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
incompleteness Things that Dafny should be able to prove, but can't
Projects
None yet
Development

No branches or pull requests

3 participants