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

Infinite loop with recursive list #531

Open
Stevendeo opened this issue Oct 28, 2022 · 3 comments
Open

Infinite loop with recursive list #531

Stevendeo opened this issue Oct 28, 2022 · 3 comments
Assignees
Labels
enhancement models This issue is related to model generation.
Milestone

Comments

@Stevendeo
Copy link
Collaborator

Alt-ergo seems to enter an infinite loop on the following example:

type 'a t = Cons of {elt : 'a; tail : 'a t} | Nil

function length (list : 'a t) : int =
  match list with
  | Nil -> 0
  | Cons(_, l') -> length(l') + 1
end

logic l : int t

goal g: length(l) <= 4
@Halbaroth
Copy link
Collaborator

Halbaroth commented Jan 12, 2023

The dolmen frontend rejects this file: Gbury/dolmen#121

@Ninjapouet Ninjapouet modified the milestone: 2.4.3 Feb 13, 2023
@bclement-ocp bclement-ocp added models This issue is related to model generation. enhancement and removed bug labels Jul 31, 2023
@bclement-ocp
Copy link
Collaborator

This is somewhat expected because the definition for length gets expanded to:

logic length : 'a t -> int

axiom length_ext : forall list : 'a t.
  length(list) =
  match list with
  | Nil -> 0
  | Cons(_, l') -> length(l') + 1
  end

and length_ext has triggers length(list) but instantiating length causes the definition to trigger again immeidately (actually in the next round I think) on the tail.

The smt2 version of that file is:

(set-logic ALL)

(declare-datatype List
  (par (A) ((cons (elt A) (tail (List A))) (nil))))

(define-fun-rec length ((l (List Int))) Int
  (ite ((_ is nil) l)
       1
       (+ (length (tail l)) 1)))

(declare-const l (List Int))
(assert (not (<= (length l) 4)))

(check-sat)

where we also loop.

Z3 has specific support for recursive functions (I have already mentioned this offline, and still think it would be worth it to explore a similar implementation) and answers sat here, but also goes into an infinite loop if we give it the "raw" definition instead:

(declare-fun length ((List Int)) Int)

(assert
(forall ((l (List Int)))
 (=
   (length l)
   (ite ((_ is nil) l)
        0
        (+ (length (tail l)) 1)))))

CVC5 terminates quickly in both cases and answers unknown, but I am not entirely sure by what logic exactly. One thing that comes to mind is we can notice that a "ground" model has been found, i.e. a model for which we have length(x) > 4 and the quantified axioms are true for all the ground terms in the model (but that has its own issues).

In any case, we need some feedback from model generation somehow to stop us from expanding the definition infinitely. Another thing we could investigate is to wait until we have learnt (either through propagation or through a sat-solver decision) that we are exploring the "then" branch before triggering the next instantiation -- I don't know if we do that currently.

@Halbaroth
Copy link
Collaborator

After #1087, the infinite loop disappeared but the current implementation of #1093 produces a wrong model. I'll investigate what's happened.

@Halbaroth Halbaroth added this to the 2.6.0 milestone Aug 14, 2024
@bclement-ocp bclement-ocp modified the milestones: 2.6.0, 2.7.0 Aug 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement models This issue is related to model generation.
Projects
None yet
Development

No branches or pull requests

4 participants