Compare commits
95 Commits
v0.4.0-bet
...
v0.4.0-bet
Author | SHA1 | Date | |
---|---|---|---|
bd108886dd
|
|||
12688a7bbe
|
|||
68dba77156
|
|||
5d931ab7e6
|
|||
f169931eac
|
|||
27fff47c91
|
|||
fc34aadf90
|
|||
4ec8bb56b9
|
|||
9b6632cc94
|
|||
93db8d02b5
|
|||
b94ee5134a
|
|||
dab121c684
|
|||
7895bf83c4
|
|||
c05eb11855
|
|||
e686575ebf
|
|||
e57a1859d2
|
|||
b52ca236e2
|
|||
bd9e0bd709
|
|||
c3b149a473
|
|||
b80b3bf6d6
|
|||
d72e2af49a
|
|||
870fdd048c
|
|||
1e55f733d0
|
|||
fe277b6773
|
|||
1b827edd45
|
|||
491a255811
|
|||
9b7895a032
|
|||
499fa0c667
|
|||
739cae1f7c
|
|||
116f74f63e
|
|||
0578e99dc2
|
|||
3b3f9017ba
|
|||
81ddfd450a
|
|||
b62c379b97
|
|||
efe354faad
|
|||
efa5656e39
|
|||
d88ac89b01
|
|||
86d2857494
|
|||
d77c7648b3
|
|||
34b8dce9be
|
|||
7020bc0bf0
|
|||
0229adef78
|
|||
c1038b398c
|
|||
3bf981236a
|
|||
4de4cc21da
|
|||
80d39c8c0a
|
|||
e2281042c9
|
|||
ce51d14a9e
|
|||
58d89b4d07
|
|||
c0bfbc923c
|
|||
0cce3bf54d
|
|||
7361084eaf
|
|||
82422cc28f
|
|||
84031c483b
|
|||
b308847ebd
|
|||
d35d0d1d98
|
|||
0dbf30bb1b
|
|||
4d00fbeb97
|
|||
07fc6a7f85
|
|||
37f0fff09f
|
|||
f39393ebce
|
|||
9621cb1e0c
|
|||
8153352b66
|
|||
e42fd92d4b
|
|||
32b18e2b63
|
|||
2f48e51244
|
|||
0d63a721c7
|
|||
e5d8a8a96b
|
|||
222f8b535e
|
|||
9ffd987e10
|
|||
7d06601c17
|
|||
2de8a59b63
|
|||
eab3520e44
|
|||
fed095ba5c
|
|||
78935f7c4a
|
|||
674cee0e87
|
|||
2ed1e6d89d
|
|||
ab7c6d1828
|
|||
2dff164d90
|
|||
b5d049a82a
|
|||
e0b8b1c854
|
|||
0d51053b88
|
|||
7c36c4b239
|
|||
0011fd9d4c
|
|||
2c660ff902
|
|||
cede63b7e4
|
|||
7a6fab59ef
|
|||
6bf01db51a
|
|||
7832f18ffd
|
|||
ee1539e2ab
|
|||
17d2373e0d
|
|||
e03628ec66
|
|||
37f1b301b5
|
|||
91765a7a15
|
|||
c075f99093
|
@@ -1,15 +1,18 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "anthem"
|
name = "anthem"
|
||||||
version = "0.4.0-beta.1"
|
version = "0.4.0-beta.2"
|
||||||
authors = ["Patrick Lühne <patrick@luehne.de>"]
|
authors = ["Patrick Lühne <patrick@luehne.de>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
atty = "0.2"
|
||||||
foliage = {git = "https://github.com/pluehne/foliage", branch = "parser-new"}
|
foliage = {git = "https://github.com/pluehne/foliage", branch = "parser-new"}
|
||||||
|
itertools = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pretty_env_logger = "0.4"
|
pretty_env_logger = "0.4"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
structopt = "0.3"
|
structopt = "0.3"
|
||||||
|
termcolor = "1.1"
|
||||||
|
|
||||||
[dependencies.clingo]
|
[dependencies.clingo]
|
||||||
git = "https://github.com/potassco/clingo-rs"
|
git = "https://github.com/potassco/clingo-rs"
|
||||||
|
@@ -1,10 +0,0 @@
|
|||||||
axiom: forall X (is_int(X) <-> exists N X = N).
|
|
||||||
|
|
||||||
input: n -> integer, s/2, is_int/1.
|
|
||||||
|
|
||||||
assume: n >= 0.
|
|
||||||
assume: forall X, Y (s(X, Y) -> is_int(Y)).
|
|
||||||
|
|
||||||
assert: forall X (in(X) -> X >= 1 and X <= n).
|
|
||||||
assert: forall X (exists I s(X, I) -> exists I (in(I) and s(X, I))).
|
|
||||||
assert: forall I, J (exists X (s(X, I) and s(X, J)) and in(I) and in(J) -> I = J).
|
|
3
examples/example-0.spec
Normal file
3
examples/example-0.spec
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
input: p/2.
|
||||||
|
|
||||||
|
spec: exists X, Y p(X, Y) <-> exists X q(X).
|
8
examples/example-1.spec
Normal file
8
examples/example-1.spec
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
input: p/1.
|
||||||
|
|
||||||
|
spec:
|
||||||
|
forall N
|
||||||
|
(
|
||||||
|
forall X (p(X) -> exists I exists M (I = M and I = X and I <= N))
|
||||||
|
-> forall X (q(X) -> exists I exists M (I = M and I = X and I <= 2 * N))
|
||||||
|
).
|
@@ -1,20 +0,0 @@
|
|||||||
axiom: forall X (isint(X) <-> exists N X = N).
|
|
||||||
axiom: forall N1, N2, N3 (N1 > N2 and N3 > 0 -> N1 * N3 > N2 * N3).
|
|
||||||
|
|
||||||
axiom: p(0) and forall N (N >= 0 and p(N) -> p(N + 1)).
|
|
||||||
|
|
||||||
input: n -> integer.
|
|
||||||
|
|
||||||
assumption: n >= 0.
|
|
||||||
|
|
||||||
assertion: exists N (forall X (q(X) <-> X = N) and N >= 0 and N * N <= n and (N + 1) * (N + 1) > n).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
lemma(forward): forall N N * N >= N.
|
|
||||||
lemma(forward): forall X (q(X) -> exists N X = N).
|
|
||||||
lemma(forward): forall X (p(X) <-> exists N2 (X = N2 and N2 >= 0 and N2 * N2 <= n)).
|
|
||||||
lemma(forward): forall X (q(X) <-> exists N2 (X = N2 and N2 >= 0 and N2 * N2 <= n and not p(N2 + 1))).
|
|
||||||
lemma(forward): forall N2 (N2 >= 0 and not p(N2 + 1) -> (N2 + 1) * (N2 + 1) > n).
|
|
||||||
lemma(forward): forall X (q(X) <-> exists N2 (X = N2 and N2 >= 0 and N2 * N2 <= n and (N2 + 1) * (N2 + 1) > n)).
|
|
||||||
lemma(forward): exists N2 (forall X (X = N2 -> (q(X) <-> N2 >= 0 and N2 * N2 <= n and (N2 + 1) * (N2 + 1) > n))).
|
|
20
examples/example-2.lemmas
Normal file
20
examples/example-2.lemmas
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Multiplication with positive numbers preserves the order of integers
|
||||||
|
axiom: forall N1, N2, N3 (N1 > N2 and N3 > 0 -> N1 * N3 > N2 * N3).
|
||||||
|
|
||||||
|
# Induction principle instantiated for p.
|
||||||
|
# This axiom is necessary because we use Vampire without higher-order reasoning
|
||||||
|
axiom: forall N1 (p(N1) and forall N2 (N2 >= N1 and not p(N2) -> not p(N2 + 1)) -> forall N2 (N2 >= N1 -> p(N2))).
|
||||||
|
#axiom: p(0) and forall N (N >= 0 and p(N) -> p(N + 1)) -> forall N p(N).
|
||||||
|
|
||||||
|
lemma(forward): forall X (p(X) <-> exists N (X = N and N >= 0 and N * N <= n)).
|
||||||
|
lemma(forward): forall X (q(X) <-> exists N2 (X = N2 and N2 >= 0 and N2 * N2 <= n and (N2 + 1) * (N2 + 1) > n)).
|
||||||
|
lemma(forward): forall N1, N2 (N1 >= 0 and N2 >= 0 and N1 < N2 -> N1 * N1 < N2 * N2).
|
||||||
|
lemma(forward): forall N (N >= 0 and p(N + 1) -> p(N)).
|
||||||
|
lemma(forward): not p(n + 1).
|
||||||
|
lemma(forward): forall N1, N2 (q(N1) and N2 > N1 -> not q(N2)).
|
||||||
|
lemma(forward): forall N (N >= 0 and not p(N + 1) -> (N + 1) * (N + 1) > n).
|
||||||
|
|
||||||
|
lemma(backward): forall N1, N2 (q(N1) and q(N2) -> N1 = N2).
|
||||||
|
axiom: forall N1, N2 (p(N1) and not p(N1 + 1) and p(N2) and not p(N2 + 1) -> N1 = N2).
|
||||||
|
|
||||||
|
lemma(backward): forall X1 (q(X1) -> p(X1) and exists X2 (exists N (X2 = N + 1 and N = X1) and not p(X2))).
|
@@ -1,30 +1,9 @@
|
|||||||
|
# Perform the proofs under the assumption that n is a nonnegative integer input constant
|
||||||
input: n -> integer.
|
input: n -> integer.
|
||||||
|
|
||||||
axiom: forall N1, N2, N3 (N1 > N2 and N3 > 0 -> N1 * N3 > N2 * N3).
|
|
||||||
axiom: (p(0) and forall N (N >= 0 and p(N) -> p(N + 1))) -> (forall N p(N)).
|
|
||||||
|
|
||||||
assume: n >= 0.
|
assume: n >= 0.
|
||||||
|
|
||||||
assert: exists N (forall X (q(X) <-> X = N) and N >= 0 and N * N <= n and (N + 1) * (N + 1) > n).
|
# p/1 is an auxiliary predicate
|
||||||
|
output: q/1.
|
||||||
|
|
||||||
|
# Verify that q computes the floor of the square root of n
|
||||||
|
spec: exists N (forall X (q(X) <-> X = N) and N >= 0 and N * N <= n and (N + 1) * (N + 1) > n).
|
||||||
lemma(forward): forall N N * N >= N.
|
|
||||||
lemma(forward): forall X (q(X) -> exists N X = N).
|
|
||||||
lemma(forward): forall X (p(X) <-> exists N2 (X = N2 and N2 >= 0 and N2 * N2 <= n)).
|
|
||||||
lemma(forward): forall X (q(X) <-> exists N2 (X = N2 and N2 >= 0 and N2 * N2 <= n and not p(N2 + 1))).
|
|
||||||
lemma(forward): forall N2 (N2 >= 0 and not p(N2 + 1) -> (N2 + 1) * (N2 + 1) > n).
|
|
||||||
lemma(forward): forall X (q(X) <-> exists N2 (X = N2 and N2 >= 0 and N2 * N2 <= n and (N2 + 1) * (N2 + 1) > n)).
|
|
||||||
|
|
||||||
|
|
||||||
lemma(forward): exists N2 (forall X (X = N2 -> (q(X) <-> N2 >= 0 and N2 * N2 <= n and (N2 + 1) * (N2 + 1) > n))).
|
|
||||||
lemma(forward): exists N2 p(N2).
|
|
||||||
lemma(forward): forall N1, N2 (N1 >= 0 and N2 >= 0 and N1 < N2 -> N1 * N1 < N2 * N2).
|
|
||||||
lemma(forward): forall N (N >= 0 and p(N + 1) -> p(N)).
|
|
||||||
|
|
||||||
lemma(forward): not p(n + 1).
|
|
||||||
lemma(forward): forall N1, N2 (N2 > N1 and N1 >= 0 and p(N2) -> p(N1)).
|
|
||||||
|
|
||||||
lemma(forward): forall N (N >= 0 -> p(N)).
|
|
||||||
|
|
||||||
lemma(forward): forall N2, N3 (q(N2) and N3 > N2 -> not q(N3)).
|
|
||||||
|
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
:- I != J, in(I), in(J), s(X, I), s(X, J).
|
:- I != J, in(I), in(J), s(X, I), s(X, J).
|
||||||
covered(X) :- in(I), s(X, I).
|
covered(X) :- in(I), s(X, I).
|
||||||
:- s(X, Y), not covered(X).
|
:- s(X, I), not covered(X).
|
22
examples/example-exact-cover.spec
Normal file
22
examples/example-exact-cover.spec
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Perform the proofs under the assumption that n is a nonnegative integer input constant. n stands
|
||||||
|
# for the total number of input sets
|
||||||
|
input: n -> integer.
|
||||||
|
assume: n >= 0.
|
||||||
|
|
||||||
|
# s/2 is the input predicate defining the sets for which the program searches for exact covers
|
||||||
|
input: s/2.
|
||||||
|
|
||||||
|
# Only the in/1 predicate is an actual output, s/2 is an input and covered/1 and is_int/1 are
|
||||||
|
# auxiliary
|
||||||
|
output: in/1.
|
||||||
|
|
||||||
|
# Perform the proofs under the assumption that the second parameter of s/2 (the number of the set)
|
||||||
|
# is always an integer
|
||||||
|
assume: forall Y (exists X s(X, Y) -> exists N (Y = N and N >= 1 and N <= n)).
|
||||||
|
|
||||||
|
# Only valid sets can be included in the solution
|
||||||
|
spec: forall Y (in(Y) -> exists N (Y = N and N >= 1 and N <= n)).
|
||||||
|
# If an element is contained in an input set, it must be covered by all solutions
|
||||||
|
spec: forall X (exists Y s(X, Y) -> exists Y (in(Y) and s(X, Y))).
|
||||||
|
# Elements may not be covered by two input sets
|
||||||
|
spec: forall Y, Z (exists X (s(X, Y) and s(X, Z)) and in(Y) and in(Z) -> Y = Z).
|
1
examples/example-prime.lemmas
Normal file
1
examples/example-prime.lemmas
Normal file
@@ -0,0 +1 @@
|
|||||||
|
lemma(backward): forall N (composite(N) <-> N > 1 and N <= n and exists I, J (I > 1 and J > 1 and I * J = N)).
|
3
examples/example-prime.lp
Normal file
3
examples/example-prime.lp
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
% Prime numbers from 1 to n.
|
||||||
|
composite(N) :- N = 1..n, I = 2..(N - 1), N \ I = 0.
|
||||||
|
prime(N) :- N = 2..n, not composite(N).
|
7
examples/example-prime.spec
Normal file
7
examples/example-prime.spec
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
input: n -> integer.
|
||||||
|
output: prime/1.
|
||||||
|
|
||||||
|
assume: n >= 1.
|
||||||
|
|
||||||
|
spec: forall X (prime(X) -> exists N (X = N)).
|
||||||
|
spec: forall N (prime(N) <-> N > 1 and N <= n and not exists I, J (I > 1 and J > 1 and I * J = N)).
|
560
src/ast.rs
Normal file
560
src/ast.rs
Normal file
@@ -0,0 +1,560 @@
|
|||||||
|
pub struct FoliageFlavor;
|
||||||
|
|
||||||
|
pub struct FunctionDeclaration
|
||||||
|
{
|
||||||
|
pub declaration: foliage::FunctionDeclaration,
|
||||||
|
pub domain: std::cell::RefCell<crate::Domain>,
|
||||||
|
pub is_input: std::cell::RefCell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionDeclaration
|
||||||
|
{
|
||||||
|
pub fn is_built_in(&self) -> bool
|
||||||
|
{
|
||||||
|
self.declaration.name.starts_with("f__") && self.declaration.name.ends_with("__")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::PartialEq for FunctionDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn eq(&self, other: &Self) -> bool
|
||||||
|
{
|
||||||
|
self.declaration.eq(&other.declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::Eq for FunctionDeclaration
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::PartialOrd for FunctionDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn partial_cmp(&self, other: &FunctionDeclaration) -> Option<std::cmp::Ordering>
|
||||||
|
{
|
||||||
|
self.declaration.partial_cmp(&other.declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::Ord for FunctionDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn cmp(&self, other: &FunctionDeclaration) -> std::cmp::Ordering
|
||||||
|
{
|
||||||
|
self.declaration.cmp(&other.declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::hash::Hash for FunctionDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H)
|
||||||
|
{
|
||||||
|
self.declaration.hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl foliage::flavor::FunctionDeclaration for FunctionDeclaration
|
||||||
|
{
|
||||||
|
fn new(name: String, arity: usize) -> Self
|
||||||
|
{
|
||||||
|
Self
|
||||||
|
{
|
||||||
|
declaration: foliage::FunctionDeclaration::new(name, arity),
|
||||||
|
domain: std::cell::RefCell::new(crate::Domain::Program),
|
||||||
|
is_input: std::cell::RefCell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_name(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
self.declaration.display_name(formatter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arity(&self) -> usize
|
||||||
|
{
|
||||||
|
self.declaration.arity
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_signature(&self, other_name: &str, other_arity: usize) -> bool
|
||||||
|
{
|
||||||
|
self.declaration.matches_signature(other_name, other_arity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum PredicateDependencySign
|
||||||
|
{
|
||||||
|
OnlyPositive,
|
||||||
|
OnlyNegative,
|
||||||
|
PositiveAndNegative,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PredicateDependencySign
|
||||||
|
{
|
||||||
|
pub fn and_positive(self) -> Self
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::OnlyPositive => Self::OnlyPositive,
|
||||||
|
Self::OnlyNegative
|
||||||
|
| Self::PositiveAndNegative => Self::PositiveAndNegative,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn and_negative(self) -> Self
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::OnlyNegative => Self::OnlyNegative,
|
||||||
|
Self::OnlyPositive
|
||||||
|
| Self::PositiveAndNegative => Self::PositiveAndNegative,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_positive(&self) -> bool
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::OnlyPositive
|
||||||
|
| Self::PositiveAndNegative => true,
|
||||||
|
Self::OnlyNegative => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_negative(&self) -> bool
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::OnlyPositive => false,
|
||||||
|
Self::OnlyNegative
|
||||||
|
| Self::PositiveAndNegative => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type PredicateDependencies =
|
||||||
|
std::collections::BTreeMap<std::rc::Rc<PredicateDeclaration>, PredicateDependencySign>;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub enum PredicateDeclarationSource
|
||||||
|
{
|
||||||
|
Program,
|
||||||
|
Specification,
|
||||||
|
ProgramAndSpecification,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PredicateDeclarationSource
|
||||||
|
{
|
||||||
|
pub fn and(self, other: Self) -> Self
|
||||||
|
{
|
||||||
|
match (self, other)
|
||||||
|
{
|
||||||
|
(Self::ProgramAndSpecification, _)
|
||||||
|
| (_, Self::ProgramAndSpecification) => Self::ProgramAndSpecification,
|
||||||
|
(Self::Program, Self::Program) => Self::Program,
|
||||||
|
(Self::Specification, Self::Specification) => Self::Specification,
|
||||||
|
(Self::Program, Self::Specification)
|
||||||
|
| (Self::Specification, Self::Program) => Self::ProgramAndSpecification,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn and_specification(self) -> Self
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::Program
|
||||||
|
| Self::ProgramAndSpecification => Self::ProgramAndSpecification,
|
||||||
|
Self::Specification => Self::Specification,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_program(&self) -> bool
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::Program
|
||||||
|
| Self::ProgramAndSpecification => true,
|
||||||
|
Self::Specification => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_specification(&self) -> bool
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::Program => false,
|
||||||
|
Self::Specification
|
||||||
|
| Self::ProgramAndSpecification => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PredicateDeclaration
|
||||||
|
{
|
||||||
|
pub declaration: foliage::PredicateDeclaration,
|
||||||
|
pub source: std::cell::RefCell<PredicateDeclarationSource>,
|
||||||
|
pub dependencies: std::cell::RefCell<Option<PredicateDependencies>>,
|
||||||
|
pub is_input: std::cell::RefCell<bool>,
|
||||||
|
pub is_output: std::cell::RefCell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PredicateDeclaration
|
||||||
|
{
|
||||||
|
pub fn tptp_statement_name(&self) -> String
|
||||||
|
{
|
||||||
|
format!("{}_{}", self.declaration.name, self.declaration.arity)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_built_in(&self) -> bool
|
||||||
|
{
|
||||||
|
self.declaration.name.starts_with("p__") && self.declaration.name.ends_with("__")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_public(&self) -> bool
|
||||||
|
{
|
||||||
|
*self.is_input.borrow() || *self.is_output.borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_positive_dependencies(&self,
|
||||||
|
mut positive_dependencies: &mut std::collections::BTreeSet<
|
||||||
|
std::rc::Rc<crate::PredicateDeclaration>>)
|
||||||
|
{
|
||||||
|
let dependencies = self.dependencies.borrow();
|
||||||
|
let dependencies = match *dependencies
|
||||||
|
{
|
||||||
|
Some(ref dependencies) => dependencies,
|
||||||
|
// Input predicates don’t have completed definitions and no dependencies, so ignore them
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (dependency, sign) in dependencies.iter()
|
||||||
|
{
|
||||||
|
if positive_dependencies.contains(&*dependency)
|
||||||
|
|| dependency.is_built_in()
|
||||||
|
|| !sign.is_positive()
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
positive_dependencies.insert(std::rc::Rc::clone(dependency));
|
||||||
|
|
||||||
|
dependency.collect_positive_dependencies(&mut positive_dependencies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_private_dependencies(&self,
|
||||||
|
mut private_dependencies: &mut std::collections::BTreeSet<
|
||||||
|
std::rc::Rc<crate::PredicateDeclaration>>)
|
||||||
|
{
|
||||||
|
let dependencies = self.dependencies.borrow();
|
||||||
|
let dependencies = match *dependencies
|
||||||
|
{
|
||||||
|
Some(ref dependencies) => dependencies,
|
||||||
|
// Input predicates don’t have completed definitions and no dependencies, so ignore them
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
for dependency in dependencies.keys()
|
||||||
|
{
|
||||||
|
if private_dependencies.contains(&*dependency)
|
||||||
|
|| dependency.is_public()
|
||||||
|
|| dependency.is_built_in()
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private_dependencies.insert(std::rc::Rc::clone(dependency));
|
||||||
|
|
||||||
|
dependency.collect_private_dependencies(&mut private_dependencies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_positive_dependency_cycle(&self) -> bool
|
||||||
|
{
|
||||||
|
if self.is_built_in()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut positive_dependencies = std::collections::BTreeSet::new();
|
||||||
|
self.collect_positive_dependencies(&mut positive_dependencies);
|
||||||
|
|
||||||
|
positive_dependencies.contains(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_private_dependency_cycle(&self) -> bool
|
||||||
|
{
|
||||||
|
if self.is_public() || self.is_built_in()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut private_dependencies = std::collections::BTreeSet::new();
|
||||||
|
self.collect_private_dependencies(&mut private_dependencies);
|
||||||
|
|
||||||
|
private_dependencies.contains(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::PartialEq for PredicateDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn eq(&self, other: &Self) -> bool
|
||||||
|
{
|
||||||
|
self.declaration.eq(&other.declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::Eq for PredicateDeclaration
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::PartialOrd for PredicateDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn partial_cmp(&self, other: &PredicateDeclaration) -> Option<std::cmp::Ordering>
|
||||||
|
{
|
||||||
|
self.declaration.partial_cmp(&other.declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::Ord for PredicateDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn cmp(&self, other: &PredicateDeclaration) -> std::cmp::Ordering
|
||||||
|
{
|
||||||
|
self.declaration.cmp(&other.declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::hash::Hash for PredicateDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H)
|
||||||
|
{
|
||||||
|
self.declaration.hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl foliage::flavor::PredicateDeclaration for PredicateDeclaration
|
||||||
|
{
|
||||||
|
fn new(name: String, arity: usize) -> Self
|
||||||
|
{
|
||||||
|
Self
|
||||||
|
{
|
||||||
|
declaration: foliage::PredicateDeclaration::new(name, arity),
|
||||||
|
source: std::cell::RefCell::new(PredicateDeclarationSource::Specification),
|
||||||
|
dependencies: std::cell::RefCell::new(None),
|
||||||
|
is_input: std::cell::RefCell::new(false),
|
||||||
|
is_output: std::cell::RefCell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_name(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
self.declaration.display_name(formatter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arity(&self) -> usize
|
||||||
|
{
|
||||||
|
self.declaration.arity
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_signature(&self, other_name: &str, other_arity: usize) -> bool
|
||||||
|
{
|
||||||
|
self.declaration.matches_signature(other_name, other_arity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct GeneratedVariableName
|
||||||
|
{
|
||||||
|
pub domain: crate::Domain,
|
||||||
|
pub id: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum VariableName
|
||||||
|
{
|
||||||
|
UserDefined(String),
|
||||||
|
Generated(GeneratedVariableName),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VariableDeclaration
|
||||||
|
{
|
||||||
|
pub name: std::cell::RefCell<VariableName>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VariableDeclaration
|
||||||
|
{
|
||||||
|
pub fn new_generated(domain: crate::Domain) -> Self
|
||||||
|
{
|
||||||
|
let generated_variable_name = GeneratedVariableName
|
||||||
|
{
|
||||||
|
domain,
|
||||||
|
id: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Self
|
||||||
|
{
|
||||||
|
name: std::cell::RefCell::new(VariableName::Generated(generated_variable_name)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn domain(&self) -> Result<crate::Domain, crate::Error>
|
||||||
|
{
|
||||||
|
match *self.name.borrow()
|
||||||
|
{
|
||||||
|
VariableName::UserDefined(ref name) =>
|
||||||
|
{
|
||||||
|
let mut name_characters = name.chars();
|
||||||
|
|
||||||
|
loop
|
||||||
|
{
|
||||||
|
match name_characters.next()
|
||||||
|
{
|
||||||
|
Some('I')
|
||||||
|
| Some('J')
|
||||||
|
| Some('K')
|
||||||
|
| Some('L')
|
||||||
|
| Some('M')
|
||||||
|
| Some('N') => return Ok(crate::Domain::Integer),
|
||||||
|
Some('X')
|
||||||
|
| Some('Y')
|
||||||
|
| Some('Z') => return Ok(crate::Domain::Program),
|
||||||
|
Some('_') => continue,
|
||||||
|
_ => return Err(
|
||||||
|
crate::Error::new_variable_name_not_allowed(name.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
VariableName::Generated(ref generated_variable_name) =>
|
||||||
|
Ok(generated_variable_name.domain),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::PartialEq for VariableDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn eq(&self, other: &Self) -> bool
|
||||||
|
{
|
||||||
|
let l = self as *const Self;
|
||||||
|
let r = other as *const Self;
|
||||||
|
|
||||||
|
l.eq(&r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::Eq for VariableDeclaration
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::PartialOrd for VariableDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn partial_cmp(&self, other: &VariableDeclaration) -> Option<std::cmp::Ordering>
|
||||||
|
{
|
||||||
|
let l = self as *const VariableDeclaration;
|
||||||
|
let r = other as *const VariableDeclaration;
|
||||||
|
|
||||||
|
l.partial_cmp(&r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::Ord for VariableDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn cmp(&self, other: &VariableDeclaration) -> std::cmp::Ordering
|
||||||
|
{
|
||||||
|
let l = self as *const VariableDeclaration;
|
||||||
|
let r = other as *const VariableDeclaration;
|
||||||
|
|
||||||
|
l.cmp(&r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::hash::Hash for VariableDeclaration
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H)
|
||||||
|
{
|
||||||
|
let p = self as *const VariableDeclaration;
|
||||||
|
|
||||||
|
p.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl foliage::flavor::VariableDeclaration for VariableDeclaration
|
||||||
|
{
|
||||||
|
fn new(name: String) -> Self
|
||||||
|
{
|
||||||
|
Self
|
||||||
|
{
|
||||||
|
name: std::cell::RefCell::new(VariableName::UserDefined(name)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_name(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
match *self.name.borrow()
|
||||||
|
{
|
||||||
|
VariableName::UserDefined(ref name) => write!(formatter, "{}", name),
|
||||||
|
VariableName::Generated(ref generated_variable_name) =>
|
||||||
|
{
|
||||||
|
let variable_name_prefix = match generated_variable_name.domain
|
||||||
|
{
|
||||||
|
crate::Domain::Program => "X",
|
||||||
|
crate::Domain::Integer => "N",
|
||||||
|
};
|
||||||
|
|
||||||
|
let variable_id = match generated_variable_name.id
|
||||||
|
{
|
||||||
|
Some(id) => id,
|
||||||
|
None => unreachable!("all variable IDs should be assigned at this point"),
|
||||||
|
};
|
||||||
|
|
||||||
|
match variable_id
|
||||||
|
{
|
||||||
|
0 => write!(formatter, "{}", variable_name_prefix),
|
||||||
|
_ => write!(formatter, "{}{}", variable_name_prefix, variable_id),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_name(&self, other_name: &str) -> bool
|
||||||
|
{
|
||||||
|
match *self.name.borrow()
|
||||||
|
{
|
||||||
|
VariableName::UserDefined(ref name) => name == other_name,
|
||||||
|
// Generated variable declarations never match user-defined variables by name
|
||||||
|
VariableName::Generated(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl foliage::flavor::Flavor for FoliageFlavor
|
||||||
|
{
|
||||||
|
type FunctionDeclaration = FunctionDeclaration;
|
||||||
|
type PredicateDeclaration = PredicateDeclaration;
|
||||||
|
type VariableDeclaration = VariableDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type BinaryOperation = foliage::BinaryOperation<FoliageFlavor>;
|
||||||
|
pub type Formula = foliage::Formula<FoliageFlavor>;
|
||||||
|
pub type Formulas = foliage::Formulas<FoliageFlavor>;
|
||||||
|
pub type FunctionDeclarations = foliage::FunctionDeclarations<FoliageFlavor>;
|
||||||
|
pub type OpenFormula = foliage::OpenFormula<FoliageFlavor>;
|
||||||
|
pub type Predicate = foliage::Predicate<FoliageFlavor>;
|
||||||
|
pub type PredicateDeclarations = foliage::PredicateDeclarations<FoliageFlavor>;
|
||||||
|
pub type QuantifiedFormula = foliage::QuantifiedFormula<FoliageFlavor>;
|
||||||
|
pub type Term = foliage::Term<FoliageFlavor>;
|
||||||
|
pub type UnaryOperation = foliage::UnaryOperation<FoliageFlavor>;
|
||||||
|
pub type Variable = foliage::Variable<FoliageFlavor>;
|
||||||
|
pub type VariableDeclarationStackLayer<'p> =
|
||||||
|
foliage::VariableDeclarationStackLayer<'p, FoliageFlavor>;
|
||||||
|
pub type VariableDeclarations = foliage::VariableDeclarations<FoliageFlavor>;
|
@@ -1,57 +1,76 @@
|
|||||||
pub fn run<P>(program_path: P, specification_path: P, proof_direction: crate::ProofDirection)
|
pub fn run<P1, P2>(program_path: P1, specification_paths: &[P2],
|
||||||
|
proof_direction: crate::problem::ProofDirection, no_simplify: bool,
|
||||||
|
color_choice: crate::output::ColorChoice)
|
||||||
where
|
where
|
||||||
P: AsRef<std::path::Path>
|
P1: AsRef<std::path::Path>,
|
||||||
|
P2: AsRef<std::path::Path>,
|
||||||
{
|
{
|
||||||
//let context = crate::translate::verify_properties::Context::new();
|
let mut problem = crate::Problem::new(color_choice);
|
||||||
let mut problem = crate::Problem::new();
|
|
||||||
|
|
||||||
log::info!("reading specification “{}”", specification_path.as_ref().display());
|
for specification_path in specification_paths
|
||||||
|
|
||||||
let specification_content = match std::fs::read_to_string(specification_path.as_ref())
|
|
||||||
{
|
{
|
||||||
Ok(specification_content) => specification_content,
|
log::info!("reading specification file “{}”", specification_path.as_ref().display());
|
||||||
Err(error) =>
|
|
||||||
{
|
|
||||||
log::error!("could not access specification file: {}", error);
|
|
||||||
std::process::exit(1)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: rename to read_specification
|
let specification_content = match std::fs::read_to_string(specification_path.as_ref())
|
||||||
match crate::input::parse_specification(&specification_content, &mut problem)
|
|
||||||
{
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(error) =>
|
|
||||||
{
|
{
|
||||||
log::error!("could not read specification: {}", error);
|
Ok(specification_content) => specification_content,
|
||||||
|
Err(error) =>
|
||||||
|
{
|
||||||
|
log::error!("could not access specification file: {}", error);
|
||||||
|
std::process::exit(1)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: rename to read_specification
|
||||||
|
if let Err(error) = crate::input::parse_specification(&specification_content, &mut problem)
|
||||||
|
{
|
||||||
|
log::error!("could not read specification file: {}", error);
|
||||||
std::process::exit(1)
|
std::process::exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::info!("read specification “{}”", specification_path.as_ref().display());
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("read specification “{}”", specification_path.as_ref().display());
|
problem.process_output_predicates();
|
||||||
|
|
||||||
log::info!("reading input program “{}”", program_path.as_ref().display());
|
log::info!("reading input program “{}”", program_path.as_ref().display());
|
||||||
|
|
||||||
// TODO: make consistent with specification call (path vs. content)
|
// TODO: make consistent with specification call (path vs. content)
|
||||||
match crate::translate::verify_properties::Translator::new(&mut problem).translate(program_path)
|
if let Err(error) = crate::translate::verify_properties::Translator::new(&mut problem)
|
||||||
|
.translate(program_path)
|
||||||
{
|
{
|
||||||
Ok(_) => (),
|
log::error!("could not translate input program: {}", error);
|
||||||
Err(error) =>
|
std::process::exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(error) = problem.check_consistency(proof_direction)
|
||||||
|
{
|
||||||
|
match error.kind
|
||||||
{
|
{
|
||||||
log::error!("could not translate input program: {}", error);
|
// In forward proofs, it’s okay to use private predicates in the specification, but
|
||||||
|
// issue a warning regardless
|
||||||
|
crate::error::Kind::PrivatePredicateInSpecification(_)
|
||||||
|
if !proof_direction.requires_backward_proof() => log::warn!("{}", error),
|
||||||
|
_ =>
|
||||||
|
{
|
||||||
|
log::error!("{}", error);
|
||||||
|
std::process::exit(1)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !no_simplify
|
||||||
|
{
|
||||||
|
if let Err(error) = problem.simplify()
|
||||||
|
{
|
||||||
|
log::error!("could not simplify translated program: {}", error);
|
||||||
std::process::exit(1)
|
std::process::exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match problem.prove(proof_direction)
|
if let Err(error) = problem.prove(proof_direction)
|
||||||
{
|
{
|
||||||
Ok(()) => (),
|
log::error!("could not verify program: {}", error);
|
||||||
Err(error) =>
|
std::process::exit(1)
|
||||||
{
|
|
||||||
log::error!("could not verify program: {}", error);
|
|
||||||
std::process::exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("done");
|
|
||||||
}
|
}
|
||||||
|
105
src/error.rs
105
src/error.rs
@@ -1,3 +1,5 @@
|
|||||||
|
use foliage::flavor::VariableDeclaration as _;
|
||||||
|
|
||||||
pub type Source = Box<dyn std::error::Error>;
|
pub type Source = Box<dyn std::error::Error>;
|
||||||
|
|
||||||
pub enum Kind
|
pub enum Kind
|
||||||
@@ -15,16 +17,23 @@ pub enum Kind
|
|||||||
MissingStatementTerminator,
|
MissingStatementTerminator,
|
||||||
ParseFormula,
|
ParseFormula,
|
||||||
ExpectedIdentifier,
|
ExpectedIdentifier,
|
||||||
|
ExpectedPredicateSpecifier,
|
||||||
ParsePredicateDeclaration,
|
ParsePredicateDeclaration,
|
||||||
//ParseConstantDeclaration,
|
//ParseConstantDeclaration,
|
||||||
UnknownProofDirection(String),
|
UnknownProofDirection(String),
|
||||||
UnknownDomainIdentifier(String),
|
UnknownDomainIdentifier(String),
|
||||||
|
UnknownColorChoice(String),
|
||||||
VariableNameNotAllowed(String),
|
VariableNameNotAllowed(String),
|
||||||
WriteTPTPProgram,
|
FormulaNotClosed(std::rc::Rc<crate::VariableDeclarations>),
|
||||||
|
ProgramNotTight(std::rc::Rc<crate::PredicateDeclaration>),
|
||||||
|
PrivatePredicateCycle(std::rc::Rc<crate::PredicateDeclaration>),
|
||||||
|
NoninputPredicateInAssumption(std::rc::Rc<crate::PredicateDeclaration>),
|
||||||
|
PrivatePredicateInSpecification(std::rc::Rc<crate::PredicateDeclaration>),
|
||||||
RunVampire,
|
RunVampire,
|
||||||
// TODO: rename to something Vampire-specific
|
// TODO: rename to something Vampire-specific
|
||||||
ProveProgram(Option<i32>, String, String),
|
ProveProgram(Option<i32>, String, String),
|
||||||
ParseVampireOutput(String, String),
|
ParseVampireOutput(String, String),
|
||||||
|
IO,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Error
|
pub struct Error
|
||||||
@@ -115,6 +124,11 @@ impl Error
|
|||||||
Self::new(Kind::ExpectedIdentifier)
|
Self::new(Kind::ExpectedIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_expected_predicate_specifier() -> Self
|
||||||
|
{
|
||||||
|
Self::new(Kind::ExpectedPredicateSpecifier)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn new_parse_predicate_declaration() -> Self
|
pub(crate) fn new_parse_predicate_declaration() -> Self
|
||||||
{
|
{
|
||||||
Self::new(Kind::ParsePredicateDeclaration)
|
Self::new(Kind::ParsePredicateDeclaration)
|
||||||
@@ -130,14 +144,48 @@ impl Error
|
|||||||
Self::new(Kind::UnknownDomainIdentifier(domain_identifier))
|
Self::new(Kind::UnknownDomainIdentifier(domain_identifier))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_unknown_color_choice(color_choice: String) -> Self
|
||||||
|
{
|
||||||
|
Self::new(Kind::UnknownColorChoice(color_choice))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn new_variable_name_not_allowed(variable_name: String) -> Self
|
pub(crate) fn new_variable_name_not_allowed(variable_name: String) -> Self
|
||||||
{
|
{
|
||||||
Self::new(Kind::VariableNameNotAllowed(variable_name))
|
Self::new(Kind::VariableNameNotAllowed(variable_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_write_tptp_program<S: Into<Source>>(source: S) -> Self
|
pub(crate) fn new_formula_not_closed(free_variables: std::rc::Rc<crate::VariableDeclarations>)
|
||||||
|
-> Self
|
||||||
{
|
{
|
||||||
Self::new(Kind::WriteTPTPProgram).with(source)
|
Self::new(Kind::FormulaNotClosed(free_variables))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_program_not_tight(
|
||||||
|
predicate_declaration: std::rc::Rc<crate::PredicateDeclaration>)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
|
Self::new(Kind::ProgramNotTight(predicate_declaration))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_private_predicate_cycle(
|
||||||
|
predicate_declaration: std::rc::Rc<crate::PredicateDeclaration>)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
|
Self::new(Kind::PrivatePredicateCycle(predicate_declaration))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_noninput_predicate_in_assumption(
|
||||||
|
predicate_declaration: std::rc::Rc<crate::PredicateDeclaration>)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
|
Self::new(Kind::NoninputPredicateInAssumption(predicate_declaration))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_private_predicate_in_specification(
|
||||||
|
predicate_declaration: std::rc::Rc<crate::PredicateDeclaration>)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
|
Self::new(Kind::PrivatePredicateInSpecification(predicate_declaration))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_run_vampire<S: Into<Source>>(source: S) -> Self
|
pub(crate) fn new_run_vampire<S: Into<Source>>(source: S) -> Self
|
||||||
@@ -154,6 +202,11 @@ impl Error
|
|||||||
{
|
{
|
||||||
Self::new(Kind::ParseVampireOutput(stdout, stderr))
|
Self::new(Kind::ParseVampireOutput(stdout, stderr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_io<S: Into<Source>>(source: S) -> Self
|
||||||
|
{
|
||||||
|
Self::new(Kind::IO).with(source)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Error
|
impl std::fmt::Debug for Error
|
||||||
@@ -178,22 +231,53 @@ impl std::fmt::Debug for Error
|
|||||||
"unknown statement “{}” (allowed: axiom, assert, assume, input, lemma)",
|
"unknown statement “{}” (allowed: axiom, assert, assume, input, lemma)",
|
||||||
statement_name),
|
statement_name),
|
||||||
Kind::UnmatchedParenthesis => write!(formatter, "unmatched parenthesis"),
|
Kind::UnmatchedParenthesis => write!(formatter, "unmatched parenthesis"),
|
||||||
Kind::ParsePredicateDeclaration => write!(formatter,
|
|
||||||
"could not parse predicate declaration"),
|
|
||||||
Kind::ParseFormula => write!(formatter, "could not parse formula"),
|
Kind::ParseFormula => write!(formatter, "could not parse formula"),
|
||||||
Kind::ExpectedIdentifier => write!(formatter, "expected constant or predicate name"),
|
Kind::ExpectedIdentifier => write!(formatter, "expected constant or predicate name"),
|
||||||
|
Kind::ExpectedPredicateSpecifier =>
|
||||||
|
write!(formatter, "expected predicate specifier (examples: p/0, q/2)"),
|
||||||
Kind::ParsePredicateDeclaration => write!(formatter,
|
Kind::ParsePredicateDeclaration => write!(formatter,
|
||||||
"could not parse predicate declaration"),
|
"could not parse predicate declaration"),
|
||||||
|
// TODO: rename to ExpectedStatementTerminator
|
||||||
Kind::MissingStatementTerminator => write!(formatter,
|
Kind::MissingStatementTerminator => write!(formatter,
|
||||||
"statement not terminated with ‘.’ character"),
|
"statement not terminated with ‘.’ character"),
|
||||||
Kind::UnknownProofDirection(ref proof_direction) => write!(formatter,
|
Kind::UnknownProofDirection(ref proof_direction) => write!(formatter,
|
||||||
"unknown proof direction “{}” (allowed: integer, program)", proof_direction),
|
"unknown proof direction “{}” (allowed: integer, program)", proof_direction),
|
||||||
Kind::UnknownDomainIdentifier(ref domain_identifier) => write!(formatter,
|
Kind::UnknownDomainIdentifier(ref domain_identifier) => write!(formatter,
|
||||||
"unknown domain identifier “{}” (allowed: int, program)", domain_identifier),
|
"unknown domain identifier “{}” (allowed: int, program)", domain_identifier),
|
||||||
|
Kind::UnknownColorChoice(ref color_choice) => write!(formatter,
|
||||||
|
"unknown color choice “{}” (allowed: auto, always, never)", color_choice),
|
||||||
Kind::VariableNameNotAllowed(ref variable_name) => write!(formatter,
|
Kind::VariableNameNotAllowed(ref variable_name) => write!(formatter,
|
||||||
"variable name “{}” not allowed (program variables must start with X, Y, or Z and integer variables with I, J, K, L, M, or N)",
|
"variable name “{}” not allowed (program variables must start with X, Y, or Z and integer variables with I, J, K, L, M, or N)",
|
||||||
variable_name),
|
variable_name),
|
||||||
Kind::WriteTPTPProgram => write!(formatter, "error writing TPTP program"),
|
Kind::FormulaNotClosed(free_variable_declarations) =>
|
||||||
|
{
|
||||||
|
write!(formatter, "formula may not contain free variables (free variables in this formula: ")?;
|
||||||
|
|
||||||
|
let mut separator = "";
|
||||||
|
|
||||||
|
for free_variable_declaration in &**free_variable_declarations
|
||||||
|
{
|
||||||
|
write!(formatter, "{}", separator)?;
|
||||||
|
free_variable_declaration.display_name(formatter)?;
|
||||||
|
separator = ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(formatter, ")")
|
||||||
|
},
|
||||||
|
Kind::ProgramNotTight(ref predicate_declaration) =>
|
||||||
|
write!(formatter, "program not tight (positive recursion involving {})",
|
||||||
|
predicate_declaration.declaration),
|
||||||
|
Kind::PrivatePredicateCycle(ref predicate_declaration) =>
|
||||||
|
write!(formatter, "private recursion involving {}",
|
||||||
|
predicate_declaration.declaration),
|
||||||
|
Kind::NoninputPredicateInAssumption(ref predicate_declaration) =>
|
||||||
|
write!(formatter,
|
||||||
|
"assumption includes {}, which is not an input predicate (consider declaring {} an input predicate)",
|
||||||
|
predicate_declaration.declaration, predicate_declaration.declaration),
|
||||||
|
Kind::PrivatePredicateInSpecification(ref predicate_declaration) =>
|
||||||
|
write!(formatter,
|
||||||
|
"private predicate {} should not occur in specification (consider declaring {} an input or output predicate)",
|
||||||
|
predicate_declaration.declaration, predicate_declaration.declaration),
|
||||||
Kind::RunVampire => write!(formatter, "could not run Vampire"),
|
Kind::RunVampire => write!(formatter, "could not run Vampire"),
|
||||||
Kind::ProveProgram(exit_code, ref stdout, ref stderr) =>
|
Kind::ProveProgram(exit_code, ref stdout, ref stderr) =>
|
||||||
{
|
{
|
||||||
@@ -216,6 +300,7 @@ impl std::fmt::Debug for Error
|
|||||||
{}\
|
{}\
|
||||||
==== stderr ===========================================================\n\
|
==== stderr ===========================================================\n\
|
||||||
{}", stdout, stderr),
|
{}", stdout, stderr),
|
||||||
|
Kind::IO => write!(formatter, "input/output error"),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
if let Some(source) = &self.source
|
if let Some(source) = &self.source
|
||||||
@@ -246,3 +331,11 @@ impl std::error::Error for Error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for Error
|
||||||
|
{
|
||||||
|
fn from(error: std::io::Error) -> Self
|
||||||
|
{
|
||||||
|
Self::new_io(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,97 +1,8 @@
|
|||||||
// TODO: refactor
|
fn open_formula<'i, D>(input: &'i str, declarations: &D)
|
||||||
fn term_assign_variable_declaration_domains<D>(term: &foliage::Term, declarations: &D)
|
-> Result<(crate::OpenFormula, &'i str), crate::Error>
|
||||||
-> Result<(), crate::Error>
|
|
||||||
where
|
where
|
||||||
D: crate::traits::AssignVariableDeclarationDomain,
|
D: foliage::FindOrCreateFunctionDeclaration<crate::FoliageFlavor>
|
||||||
{
|
+ foliage::FindOrCreatePredicateDeclaration<crate::FoliageFlavor>
|
||||||
match term
|
|
||||||
{
|
|
||||||
foliage::Term::BinaryOperation(binary_operation) =>
|
|
||||||
{
|
|
||||||
term_assign_variable_declaration_domains(&binary_operation.left, declarations)?;
|
|
||||||
term_assign_variable_declaration_domains(&binary_operation.right, declarations)?;
|
|
||||||
},
|
|
||||||
foliage::Term::Function(function) =>
|
|
||||||
for argument in &function.arguments
|
|
||||||
{
|
|
||||||
term_assign_variable_declaration_domains(&argument, declarations)?;
|
|
||||||
},
|
|
||||||
foliage::Term::UnaryOperation(unary_operation) =>
|
|
||||||
term_assign_variable_declaration_domains(&unary_operation.argument, declarations)?,
|
|
||||||
foliage::Term::Variable(variable) =>
|
|
||||||
{
|
|
||||||
let domain = match variable.declaration.name.chars().next()
|
|
||||||
{
|
|
||||||
Some('X')
|
|
||||||
| Some('Y')
|
|
||||||
| Some('Z') => crate::Domain::Program,
|
|
||||||
Some('I')
|
|
||||||
| Some('J')
|
|
||||||
| Some('K')
|
|
||||||
| Some('L')
|
|
||||||
| Some('M')
|
|
||||||
| Some('N') => crate::Domain::Integer,
|
|
||||||
// TODO: improve error handling
|
|
||||||
Some(other) => return Err(
|
|
||||||
crate::Error::new_variable_name_not_allowed(variable.declaration.name.clone())),
|
|
||||||
None => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
declarations.assign_variable_declaration_domain(&variable.declaration, domain);
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn formula_assign_variable_declaration_domains<D>(formula: &foliage::Formula, declarations: &D)
|
|
||||||
-> Result<(), crate::Error>
|
|
||||||
where
|
|
||||||
D: crate::traits::AssignVariableDeclarationDomain,
|
|
||||||
{
|
|
||||||
match formula
|
|
||||||
{
|
|
||||||
foliage::Formula::And(arguments)
|
|
||||||
| foliage::Formula::Or(arguments)
|
|
||||||
| foliage::Formula::IfAndOnlyIf(arguments) =>
|
|
||||||
for argument in arguments
|
|
||||||
{
|
|
||||||
formula_assign_variable_declaration_domains(&argument, declarations)?;
|
|
||||||
},
|
|
||||||
foliage::Formula::Compare(compare) =>
|
|
||||||
{
|
|
||||||
term_assign_variable_declaration_domains(&compare.left, declarations)?;
|
|
||||||
term_assign_variable_declaration_domains(&compare.right, declarations)?;
|
|
||||||
},
|
|
||||||
foliage::Formula::Exists(quantified_formula)
|
|
||||||
| foliage::Formula::ForAll(quantified_formula) =>
|
|
||||||
formula_assign_variable_declaration_domains(&quantified_formula.argument,
|
|
||||||
declarations)?,
|
|
||||||
foliage::Formula::Implies(implies) =>
|
|
||||||
{
|
|
||||||
formula_assign_variable_declaration_domains(&implies.antecedent, declarations)?;
|
|
||||||
formula_assign_variable_declaration_domains(&implies.implication, declarations)?;
|
|
||||||
}
|
|
||||||
foliage::Formula::Not(argument) =>
|
|
||||||
formula_assign_variable_declaration_domains(&argument, declarations)?,
|
|
||||||
foliage::Formula::Predicate(predicate) =>
|
|
||||||
for argument in &predicate.arguments
|
|
||||||
{
|
|
||||||
term_assign_variable_declaration_domains(&argument, declarations)?;
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn closed_formula<'i, D>(input: &'i str, declarations: &D)
|
|
||||||
-> Result<(crate::ScopedFormula, &'i str), crate::Error>
|
|
||||||
where
|
|
||||||
D: foliage::FindOrCreateFunctionDeclaration
|
|
||||||
+ foliage::FindOrCreatePredicateDeclaration
|
|
||||||
+ crate::traits::AssignVariableDeclarationDomain,
|
|
||||||
{
|
{
|
||||||
let terminator_position = match input.find('.')
|
let terminator_position = match input.find('.')
|
||||||
{
|
{
|
||||||
@@ -104,176 +15,114 @@ where
|
|||||||
remaining_input_characters.next();
|
remaining_input_characters.next();
|
||||||
let remaining_input = remaining_input_characters.as_str();
|
let remaining_input = remaining_input_characters.as_str();
|
||||||
|
|
||||||
let closed_formula = foliage::parse::formula(formula_input, declarations)
|
let open_formula = foliage::parse::formula(formula_input, declarations)
|
||||||
.map_err(|error| crate::Error::new_parse_formula(error))?;
|
.map_err(|error| crate::Error::new_parse_formula(error))?;
|
||||||
|
|
||||||
formula_assign_variable_declaration_domains(&closed_formula.formula, declarations)?;
|
let open_formula = crate::OpenFormula
|
||||||
|
|
||||||
// TODO: get rid of ScopedFormula
|
|
||||||
let scoped_formula = crate::ScopedFormula
|
|
||||||
{
|
{
|
||||||
free_variable_declarations: closed_formula.free_variable_declarations,
|
free_variable_declarations: open_formula.free_variable_declarations,
|
||||||
formula: closed_formula.formula,
|
formula: open_formula.formula,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((scoped_formula, remaining_input))
|
Ok((open_formula, remaining_input))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn variable_free_formula<'i, D>(input: &'i str, declarations: &D)
|
fn formula<'i, D>(mut input: &'i str, declarations: &D)
|
||||||
-> Result<(foliage::Formula, &'i str), crate::Error>
|
-> Result<(crate::Formula, &'i str), crate::Error>
|
||||||
where
|
where
|
||||||
D: foliage::FindOrCreateFunctionDeclaration
|
D: foliage::FindOrCreateFunctionDeclaration<crate::FoliageFlavor>
|
||||||
+ foliage::FindOrCreatePredicateDeclaration
|
+ foliage::FindOrCreatePredicateDeclaration<crate::FoliageFlavor>
|
||||||
+ crate::traits::AssignVariableDeclarationDomain,
|
|
||||||
{
|
{
|
||||||
let (closed_formula, input) = closed_formula(input, declarations)?;
|
let (open_formula, remaining_input) = open_formula(input, declarations)?;
|
||||||
|
|
||||||
if !closed_formula.free_variable_declarations.is_empty()
|
|
||||||
{
|
|
||||||
// TODO: improve
|
|
||||||
panic!("formula may not contain free variables");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((closed_formula.formula, input))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn formula_statement_body<'i>(input: &'i str, problem: &crate::Problem)
|
|
||||||
-> Result<(foliage::Formula, &'i str), crate::Error>
|
|
||||||
{
|
|
||||||
let input = input.trim_start();
|
|
||||||
|
|
||||||
let mut input_characters = input.chars();
|
|
||||||
|
|
||||||
let remaining_input = match input_characters.next()
|
|
||||||
{
|
|
||||||
Some(':') => input_characters.as_str(),
|
|
||||||
_ => return Err(crate::Error::new_expected_colon()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let input = remaining_input;
|
|
||||||
|
|
||||||
variable_free_formula(input, problem)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input_statement_body<'i>(mut input: &'i str, problem: &crate::Problem)
|
|
||||||
-> Result<&'i str, crate::Error>
|
|
||||||
{
|
|
||||||
input = input.trim_start();
|
|
||||||
|
|
||||||
let mut input_characters = input.chars();
|
|
||||||
|
|
||||||
let remaining_input = match input_characters.next()
|
|
||||||
{
|
|
||||||
Some(':') => input_characters.as_str(),
|
|
||||||
_ => return Err(crate::Error::new_expected_colon()),
|
|
||||||
};
|
|
||||||
|
|
||||||
input = remaining_input;
|
input = remaining_input;
|
||||||
|
|
||||||
loop
|
if !open_formula.free_variable_declarations.is_empty()
|
||||||
{
|
{
|
||||||
input = input.trim_start();
|
return Err(crate::Error::new_formula_not_closed(open_formula.free_variable_declarations));
|
||||||
|
}
|
||||||
|
|
||||||
let (constant_or_predicate_name, remaining_input) =
|
Ok((open_formula.formula, input))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn formula_statement_body<'i>(mut input: &'i str, problem: &crate::Problem)
|
||||||
|
-> Result<(crate::Formula, &'i str), crate::Error>
|
||||||
|
{
|
||||||
|
input = foliage::parse::tokens::trim_start(input);
|
||||||
|
|
||||||
|
let mut input_characters = input.chars();
|
||||||
|
|
||||||
|
input = match input_characters.next()
|
||||||
|
{
|
||||||
|
Some(':') => input_characters.as_str(),
|
||||||
|
_ => return Err(crate::Error::new_expected_colon()),
|
||||||
|
};
|
||||||
|
|
||||||
|
formula(input, problem)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn domain_specifier<'i>(mut input: &'i str)
|
||||||
|
-> Result<(Option<crate::Domain>, &'i str), crate::Error>
|
||||||
|
{
|
||||||
|
let original_input = input;
|
||||||
|
input = foliage::parse::tokens::trim_start(input);
|
||||||
|
|
||||||
|
if input.starts_with("->")
|
||||||
|
{
|
||||||
|
let mut input_characters = input.chars();
|
||||||
|
input_characters.next();
|
||||||
|
input_characters.next();
|
||||||
|
|
||||||
|
input = foliage::parse::tokens::trim_start(input_characters.as_str());
|
||||||
|
|
||||||
|
let (identifier, remaining_input) =
|
||||||
foliage::parse::tokens::identifier(input)
|
foliage::parse::tokens::identifier(input)
|
||||||
.ok_or_else(|| crate::Error::new_expected_identifier())?;
|
.ok_or_else(|| crate::Error::new_expected_identifier())?;
|
||||||
|
|
||||||
input = remaining_input.trim_start();
|
input = remaining_input;
|
||||||
|
|
||||||
let mut input_characters = input.chars();
|
match identifier
|
||||||
|
|
||||||
match input_characters.next()
|
|
||||||
{
|
{
|
||||||
// Parse input predicate specifiers
|
"integer" => Ok((Some(crate::Domain::Integer), input)),
|
||||||
Some('/') =>
|
"program" => Ok((Some(crate::Domain::Program), input)),
|
||||||
{
|
_ => return Err(crate::Error::new_unknown_domain_identifier(identifier.to_string())),
|
||||||
input = input_characters.as_str().trim_start();
|
|
||||||
|
|
||||||
let (arity, remaining_input) = foliage::parse::tokens::number(input)
|
|
||||||
.map_err(|error| crate::Error::new_parse_predicate_declaration().with(error))?
|
|
||||||
.ok_or_else(|| crate::Error::new_parse_predicate_declaration())?;
|
|
||||||
|
|
||||||
input = remaining_input.trim_start();
|
|
||||||
|
|
||||||
let mut input_predicate_declarations =
|
|
||||||
problem.input_predicate_declarations.borrow_mut();
|
|
||||||
|
|
||||||
use foliage::FindOrCreatePredicateDeclaration;
|
|
||||||
|
|
||||||
let predicate_declaration =
|
|
||||||
problem.find_or_create_predicate_declaration(constant_or_predicate_name, arity);
|
|
||||||
|
|
||||||
input_predicate_declarations.insert(predicate_declaration);
|
|
||||||
|
|
||||||
let mut input_characters = input.chars();
|
|
||||||
|
|
||||||
match input_characters.next()
|
|
||||||
{
|
|
||||||
Some(',') => input = input_characters.as_str(),
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Parse input constant specifiers
|
|
||||||
Some(_)
|
|
||||||
| None =>
|
|
||||||
{
|
|
||||||
let domain =
|
|
||||||
if input.starts_with("->")
|
|
||||||
{
|
|
||||||
let mut input_characters = input.chars();
|
|
||||||
input_characters.next();
|
|
||||||
input_characters.next();
|
|
||||||
|
|
||||||
input = input_characters.as_str().trim_start();
|
|
||||||
|
|
||||||
let (identifier, remaining_input) =
|
|
||||||
foliage::parse::tokens::identifier(input)
|
|
||||||
.ok_or_else(|| crate::Error::new_expected_identifier())?;
|
|
||||||
|
|
||||||
input = remaining_input;
|
|
||||||
|
|
||||||
match identifier
|
|
||||||
{
|
|
||||||
"integer" => crate::Domain::Integer,
|
|
||||||
"program" => crate::Domain::Program,
|
|
||||||
_ => return Err(crate::Error::new_unknown_domain_identifier(
|
|
||||||
identifier.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
crate::Domain::Program
|
|
||||||
};
|
|
||||||
|
|
||||||
log::debug!("domain: {:?}", domain);
|
|
||||||
|
|
||||||
let mut input_constant_declarations =
|
|
||||||
problem.input_constant_declarations.borrow_mut();
|
|
||||||
|
|
||||||
use foliage::FindOrCreateFunctionDeclaration;
|
|
||||||
|
|
||||||
let constant_declaration =
|
|
||||||
problem.find_or_create_function_declaration(constant_or_predicate_name, 0);
|
|
||||||
|
|
||||||
input_constant_declarations.insert(std::rc::Rc::clone(&constant_declaration));
|
|
||||||
|
|
||||||
let mut input_constant_declaration_domains =
|
|
||||||
problem.input_constant_declaration_domains.borrow_mut();
|
|
||||||
|
|
||||||
input_constant_declaration_domains.insert(constant_declaration, domain);
|
|
||||||
|
|
||||||
let mut input_characters = input.chars();
|
|
||||||
|
|
||||||
match input_characters.next()
|
|
||||||
{
|
|
||||||
Some(',') => input = input_characters.as_str(),
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ok((None, original_input))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
input = input.trim_start();
|
fn predicate_arity_specifier<'i>(mut input: &'i str)
|
||||||
|
-> Result<(Option<usize>, &'i str), crate::Error>
|
||||||
|
{
|
||||||
|
let original_input = input;
|
||||||
|
input = foliage::parse::tokens::trim_start(input);
|
||||||
|
|
||||||
|
let mut input_characters = input.chars();
|
||||||
|
|
||||||
|
if input_characters.next() == Some('/')
|
||||||
|
{
|
||||||
|
input = foliage::parse::tokens::trim_start(input_characters.as_str());
|
||||||
|
|
||||||
|
let (arity, remaining_input) = foliage::parse::tokens::number(input)
|
||||||
|
.map_err(|error| crate::Error::new_parse_predicate_declaration().with(error))?
|
||||||
|
.ok_or_else(|| crate::Error::new_parse_predicate_declaration())?;
|
||||||
|
|
||||||
|
input = remaining_input;
|
||||||
|
|
||||||
|
Ok((Some(arity), input))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ok((None, original_input))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_statement_terminator<'i>(mut input: &'i str) -> Result<&'i str, crate::Error>
|
||||||
|
{
|
||||||
|
input = foliage::parse::tokens::trim_start(input);
|
||||||
|
|
||||||
let mut input_characters = input.chars();
|
let mut input_characters = input.chars();
|
||||||
|
|
||||||
@@ -287,12 +136,134 @@ fn input_statement_body<'i>(mut input: &'i str, problem: &crate::Problem)
|
|||||||
Ok(input)
|
Ok(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn input_statement_body<'i>(mut input: &'i str, problem: &crate::Problem)
|
||||||
|
-> Result<&'i str, crate::Error>
|
||||||
|
{
|
||||||
|
input = foliage::parse::tokens::trim_start(input);
|
||||||
|
|
||||||
|
let mut input_characters = input.chars();
|
||||||
|
|
||||||
|
let remaining_input = match input_characters.next()
|
||||||
|
{
|
||||||
|
Some(':') => input_characters.as_str(),
|
||||||
|
_ => return Err(crate::Error::new_expected_colon()),
|
||||||
|
};
|
||||||
|
|
||||||
|
input = remaining_input;
|
||||||
|
|
||||||
|
loop
|
||||||
|
{
|
||||||
|
input = foliage::parse::tokens::trim_start(input);
|
||||||
|
|
||||||
|
let (constant_or_predicate_name, remaining_input) =
|
||||||
|
foliage::parse::tokens::identifier(input)
|
||||||
|
.ok_or_else(|| crate::Error::new_expected_identifier())?;
|
||||||
|
|
||||||
|
input = foliage::parse::tokens::trim_start(remaining_input);
|
||||||
|
|
||||||
|
// Parse input predicate specifiers
|
||||||
|
if let (Some(arity), remaining_input) = predicate_arity_specifier(input)?
|
||||||
|
{
|
||||||
|
input = remaining_input;
|
||||||
|
|
||||||
|
let predicate_declaration =
|
||||||
|
problem.find_or_create_predicate_declaration(constant_or_predicate_name, arity,
|
||||||
|
crate::PredicateDeclarationSource::Specification);
|
||||||
|
|
||||||
|
*predicate_declaration.is_input.borrow_mut() = true;
|
||||||
|
}
|
||||||
|
// Parse input constant specifiers
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: detect conflicting domain specifiers (for example: n -> program, n -> integer)
|
||||||
|
let (domain, remaining_input) = match domain_specifier(input)?
|
||||||
|
{
|
||||||
|
(Some(domain), remaining_input) => (domain, remaining_input),
|
||||||
|
(None, remaining_input) => (crate::Domain::Program, remaining_input),
|
||||||
|
};
|
||||||
|
|
||||||
|
input = remaining_input;
|
||||||
|
|
||||||
|
use foliage::FindOrCreateFunctionDeclaration as _;
|
||||||
|
|
||||||
|
let constant_declaration =
|
||||||
|
problem.find_or_create_function_declaration(constant_or_predicate_name, 0);
|
||||||
|
|
||||||
|
*constant_declaration.is_input.borrow_mut() = true;
|
||||||
|
*constant_declaration.domain.borrow_mut() = domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut input_characters = input.chars();
|
||||||
|
|
||||||
|
match input_characters.next()
|
||||||
|
{
|
||||||
|
Some(',') => input = input_characters.as_str(),
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_statement_terminator(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_statement_body<'i>(mut input: &'i str, problem: &crate::Problem)
|
||||||
|
-> Result<&'i str, crate::Error>
|
||||||
|
{
|
||||||
|
input = foliage::parse::tokens::trim_start(input);
|
||||||
|
|
||||||
|
let mut input_characters = input.chars();
|
||||||
|
|
||||||
|
let remaining_input = match input_characters.next()
|
||||||
|
{
|
||||||
|
Some(':') => input_characters.as_str(),
|
||||||
|
_ => return Err(crate::Error::new_expected_colon()),
|
||||||
|
};
|
||||||
|
|
||||||
|
input = remaining_input;
|
||||||
|
|
||||||
|
loop
|
||||||
|
{
|
||||||
|
input = foliage::parse::tokens::trim_start(input);
|
||||||
|
|
||||||
|
let (constant_or_predicate_name, remaining_input) =
|
||||||
|
foliage::parse::tokens::identifier(input)
|
||||||
|
.ok_or_else(|| crate::Error::new_expected_identifier())?;
|
||||||
|
|
||||||
|
input = foliage::parse::tokens::trim_start(remaining_input);
|
||||||
|
|
||||||
|
// Only accept output predicate specifiers
|
||||||
|
if let (Some(arity), remaining_input) = predicate_arity_specifier(input)?
|
||||||
|
{
|
||||||
|
input = remaining_input;
|
||||||
|
|
||||||
|
let predicate_declaration =
|
||||||
|
problem.find_or_create_predicate_declaration(constant_or_predicate_name, arity,
|
||||||
|
crate::PredicateDeclarationSource::Specification);
|
||||||
|
|
||||||
|
*predicate_declaration.is_output.borrow_mut() = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Err(crate::Error::new_expected_predicate_specifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut input_characters = input.chars();
|
||||||
|
|
||||||
|
match input_characters.next()
|
||||||
|
{
|
||||||
|
Some(',') => input = input_characters.as_str(),
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_statement_terminator(input)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_specification(mut input: &str, problem: &crate::Problem)
|
pub(crate) fn parse_specification(mut input: &str, problem: &crate::Problem)
|
||||||
-> Result<(), crate::Error>
|
-> Result<(), crate::Error>
|
||||||
{
|
{
|
||||||
loop
|
loop
|
||||||
{
|
{
|
||||||
input = input.trim_start();
|
input = foliage::parse::tokens::trim_start(input);
|
||||||
|
|
||||||
if input.is_empty()
|
if input.is_empty()
|
||||||
{
|
{
|
||||||
@@ -335,7 +306,7 @@ pub(crate) fn parse_specification(mut input: &str, problem: &crate::Problem)
|
|||||||
},
|
},
|
||||||
"lemma" =>
|
"lemma" =>
|
||||||
{
|
{
|
||||||
input = input.trim_start();
|
input = foliage::parse::tokens::trim_start(input);
|
||||||
|
|
||||||
let mut input_characters = input.chars();
|
let mut input_characters = input.chars();
|
||||||
|
|
||||||
@@ -344,24 +315,24 @@ pub(crate) fn parse_specification(mut input: &str, problem: &crate::Problem)
|
|||||||
Some('(') =>
|
Some('(') =>
|
||||||
{
|
{
|
||||||
// TODO: refactor
|
// TODO: refactor
|
||||||
input = input_characters.as_str().trim_start();
|
input = foliage::parse::tokens::trim_start(input_characters.as_str());
|
||||||
|
|
||||||
let (proof_direction, remaining_input) = match
|
let (proof_direction, remaining_input) = match
|
||||||
foliage::parse::tokens::identifier(input)
|
foliage::parse::tokens::identifier(input)
|
||||||
{
|
{
|
||||||
Some(("forward", remaining_input)) =>
|
Some(("forward", remaining_input)) =>
|
||||||
(crate::ProofDirection::Forward, remaining_input),
|
(crate::problem::ProofDirection::Forward, remaining_input),
|
||||||
Some(("backward", remaining_input)) =>
|
Some(("backward", remaining_input)) =>
|
||||||
(crate::ProofDirection::Backward, remaining_input),
|
(crate::problem::ProofDirection::Backward, remaining_input),
|
||||||
Some(("both", remaining_input)) =>
|
Some(("both", remaining_input)) =>
|
||||||
(crate::ProofDirection::Both, remaining_input),
|
(crate::problem::ProofDirection::Both, remaining_input),
|
||||||
Some((identifier, _)) =>
|
Some((identifier, _)) =>
|
||||||
return Err(crate::Error::new_unknown_proof_direction(
|
return Err(crate::Error::new_unknown_proof_direction(
|
||||||
identifier.to_string())),
|
identifier.to_string())),
|
||||||
None => (crate::ProofDirection::Both, input),
|
None => (crate::problem::ProofDirection::Both, input),
|
||||||
};
|
};
|
||||||
|
|
||||||
input = remaining_input.trim_start();
|
input = foliage::parse::tokens::trim_start(remaining_input);
|
||||||
|
|
||||||
let mut input_characters = input.chars();
|
let mut input_characters = input.chars();
|
||||||
|
|
||||||
@@ -375,7 +346,7 @@ pub(crate) fn parse_specification(mut input: &str, problem: &crate::Problem)
|
|||||||
(proof_direction, input)
|
(proof_direction, input)
|
||||||
},
|
},
|
||||||
Some(_)
|
Some(_)
|
||||||
| None => (crate::ProofDirection::Both, remaining_input),
|
| None => (crate::problem::ProofDirection::Both, remaining_input),
|
||||||
};
|
};
|
||||||
|
|
||||||
input = remaining_input;
|
input = remaining_input;
|
||||||
@@ -391,20 +362,21 @@ pub(crate) fn parse_specification(mut input: &str, problem: &crate::Problem)
|
|||||||
|
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
"assert" =>
|
"spec" =>
|
||||||
{
|
{
|
||||||
let (formula, remaining_input) = formula_statement_body(input, problem)?;
|
let (formula, remaining_input) = formula_statement_body(input, problem)?;
|
||||||
|
|
||||||
input = remaining_input;
|
input = remaining_input;
|
||||||
|
|
||||||
let statement = crate::problem::Statement::new(
|
let statement = crate::problem::Statement::new(
|
||||||
crate::problem::StatementKind::Assertion, formula);
|
crate::problem::StatementKind::Spec, formula);
|
||||||
|
|
||||||
problem.add_statement(crate::problem::SectionKind::Assertions, statement);
|
problem.add_statement(crate::problem::SectionKind::Specs, statement);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
"input" => input = input_statement_body(input, problem)?,
|
"input" => input = input_statement_body(input, problem)?,
|
||||||
|
"output" => input = output_statement_body(input, problem)?,
|
||||||
identifier => return Err(crate::Error::new_unknown_statement(identifier.to_string())),
|
identifier => return Err(crate::Error::new_unknown_statement(identifier.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,15 +1,19 @@
|
|||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
|
#![feature(vec_remove_item)]
|
||||||
|
|
||||||
|
mod ast;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
pub mod problem;
|
pub mod problem;
|
||||||
pub(crate) mod traits;
|
pub mod simplify;
|
||||||
pub mod translate;
|
pub mod translate;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
pub use crate::ast::*;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use problem::Problem;
|
pub use problem::Problem;
|
||||||
|
pub(crate) use simplify::*;
|
||||||
pub(crate) use utils::*;
|
pub(crate) use utils::*;
|
||||||
pub use utils::{Domain, InputConstantDeclarationDomains, ProofDirection};
|
pub use utils::Domain;
|
||||||
|
24
src/main.rs
24
src/main.rs
@@ -13,12 +13,20 @@ enum Command
|
|||||||
program_path: std::path::PathBuf,
|
program_path: std::path::PathBuf,
|
||||||
|
|
||||||
#[structopt(name = "specification", parse(from_os_str), required(true))]
|
#[structopt(name = "specification", parse(from_os_str), required(true))]
|
||||||
/// Specification file path
|
/// One or more specification file paths
|
||||||
specification_path: std::path::PathBuf,
|
specification_paths: Vec<std::path::PathBuf>,
|
||||||
|
|
||||||
/// Proof direction (forward, backward, both)
|
/// Proof direction (forward, backward, both)
|
||||||
#[structopt(long, default_value = "forward")]
|
#[structopt(long, default_value = "both")]
|
||||||
proof_direction: anthem::ProofDirection,
|
proof_direction: anthem::problem::ProofDirection,
|
||||||
|
|
||||||
|
/// Do not simplify translated program
|
||||||
|
#[structopt(long)]
|
||||||
|
no_simplify: bool,
|
||||||
|
|
||||||
|
/// Whether to use colors in the output (auto, always, never)
|
||||||
|
#[structopt(name = "color", long, default_value = "auto")]
|
||||||
|
color_choice: anthem::output::ColorChoice,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,10 +41,12 @@ fn main()
|
|||||||
Command::VerifyProgram
|
Command::VerifyProgram
|
||||||
{
|
{
|
||||||
program_path,
|
program_path,
|
||||||
specification_path,
|
specification_paths,
|
||||||
proof_direction,
|
proof_direction,
|
||||||
|
no_simplify,
|
||||||
|
color_choice,
|
||||||
}
|
}
|
||||||
=> anthem::commands::verify_program::run(&program_path, &specification_path,
|
=> anthem::commands::verify_program::run(&program_path, specification_paths.as_slice(),
|
||||||
proof_direction),
|
proof_direction, no_simplify, color_choice),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
pub(crate) mod human_readable;
|
pub(crate) mod shell;
|
||||||
pub(crate) mod tptp;
|
pub(crate) mod tptp;
|
||||||
|
|
||||||
|
pub use shell::ColorChoice;
|
||||||
|
pub(crate) use shell::Shell;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
pub enum Format
|
pub enum Format
|
||||||
{
|
{
|
||||||
|
@@ -1,18 +0,0 @@
|
|||||||
/*pub(crate) fn display_variable_declaration<C>(context: &C, formatter: &mut std::fmt::Formatter,
|
|
||||||
variable_declaration: &std::rc::Rc<foliage::VariableDeclaration>)
|
|
||||||
-> std::fmt::Result
|
|
||||||
where C:
|
|
||||||
crate::traits::VariableDeclarationDomain + crate::traits::VariableDeclarationID
|
|
||||||
{
|
|
||||||
let id = context.variable_declaration_id(variable_declaration);
|
|
||||||
let domain = context.variable_declaration_domain(variable_declaration)
|
|
||||||
.expect("unspecified variable domain");
|
|
||||||
|
|
||||||
let prefix = match domain
|
|
||||||
{
|
|
||||||
crate::Domain::Integer => "N",
|
|
||||||
crate::Domain::Program => "X",
|
|
||||||
};
|
|
||||||
|
|
||||||
write!(formatter, "{}{}", prefix, id + 1)
|
|
||||||
}*/
|
|
149
src/output/shell.rs
Normal file
149
src/output/shell.rs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
pub struct Shell
|
||||||
|
{
|
||||||
|
output: ShellOutput,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ShellOutput
|
||||||
|
{
|
||||||
|
Basic(Box<dyn std::io::Write>),
|
||||||
|
WithColorSupport(termcolor::StandardStream),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub enum ColorChoice
|
||||||
|
{
|
||||||
|
Always,
|
||||||
|
Never,
|
||||||
|
Auto,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shell
|
||||||
|
{
|
||||||
|
pub fn from_stdout(color_choice: ColorChoice) -> Self
|
||||||
|
{
|
||||||
|
Self
|
||||||
|
{
|
||||||
|
output: match color_choice
|
||||||
|
{
|
||||||
|
ColorChoice::Never => ShellOutput::Basic(Box::new(std::io::stdout())),
|
||||||
|
_ => ShellOutput::WithColorSupport(termcolor::StandardStream::stdout(
|
||||||
|
color_choice.to_termcolor_color_choice())),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print(&mut self, text: &dyn std::fmt::Display, color: &termcolor::ColorSpec)
|
||||||
|
-> std::io::Result<()>
|
||||||
|
{
|
||||||
|
self.output.print(text, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn println(&mut self, text: &dyn std::fmt::Display, color: &termcolor::ColorSpec)
|
||||||
|
-> std::io::Result<()>
|
||||||
|
{
|
||||||
|
self.output.println(text, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn erase_line(&mut self)
|
||||||
|
{
|
||||||
|
self.output.erase_line();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShellOutput
|
||||||
|
{
|
||||||
|
fn print(&mut self, text: &dyn std::fmt::Display, color: &termcolor::ColorSpec)
|
||||||
|
-> std::io::Result<()>
|
||||||
|
{
|
||||||
|
use std::io::Write as _;
|
||||||
|
use termcolor::WriteColor as _;
|
||||||
|
|
||||||
|
match *self
|
||||||
|
{
|
||||||
|
Self::Basic(ref mut write) => write!(write, "{}", text),
|
||||||
|
Self::WithColorSupport(ref mut stream) =>
|
||||||
|
{
|
||||||
|
stream.reset()?;
|
||||||
|
stream.set_color(color)?;
|
||||||
|
|
||||||
|
write!(stream, "{}", text)?;
|
||||||
|
|
||||||
|
stream.reset()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn println(&mut self, text: &dyn std::fmt::Display, color: &termcolor::ColorSpec)
|
||||||
|
-> std::io::Result<()>
|
||||||
|
{
|
||||||
|
self.print(text, color)?;
|
||||||
|
|
||||||
|
use std::io::Write as _;
|
||||||
|
|
||||||
|
match *self
|
||||||
|
{
|
||||||
|
Self::Basic(ref mut write) => writeln!(write, ""),
|
||||||
|
Self::WithColorSupport(ref mut stream) => writeln!(stream, ""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn erase_line(&mut self)
|
||||||
|
{
|
||||||
|
let erase_sequence = b"\x1b[2K";
|
||||||
|
|
||||||
|
use std::io::Write as _;
|
||||||
|
|
||||||
|
let _ = match *self
|
||||||
|
{
|
||||||
|
Self::Basic(ref mut write) => write.write_all(erase_sequence),
|
||||||
|
Self::WithColorSupport(ref mut stream) => stream.write_all(erase_sequence),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorChoice
|
||||||
|
{
|
||||||
|
fn to_termcolor_color_choice(self) -> termcolor::ColorChoice
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::Always => termcolor::ColorChoice::Always,
|
||||||
|
Self::Never => termcolor::ColorChoice::Never,
|
||||||
|
Self::Auto => match atty::is(atty::Stream::Stdout)
|
||||||
|
{
|
||||||
|
true => termcolor::ColorChoice::Auto,
|
||||||
|
false => termcolor::ColorChoice::Never,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for ColorChoice
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
ColorChoice::Always => write!(formatter, "always"),
|
||||||
|
ColorChoice::Never => write!(formatter, "never"),
|
||||||
|
ColorChoice::Auto => write!(formatter, "auto"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for ColorChoice
|
||||||
|
{
|
||||||
|
type Err = crate::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err>
|
||||||
|
{
|
||||||
|
match s
|
||||||
|
{
|
||||||
|
"always" => Ok(ColorChoice::Always),
|
||||||
|
"never" => Ok(ColorChoice::Never),
|
||||||
|
"auto" => Ok(ColorChoice::Auto),
|
||||||
|
_ => Err(crate::Error::new_unknown_color_choice(s.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,3 +1,6 @@
|
|||||||
|
use foliage::flavor::{FunctionDeclaration as _, PredicateDeclaration as _,
|
||||||
|
VariableDeclaration as _};
|
||||||
|
|
||||||
pub(crate) struct DomainDisplay
|
pub(crate) struct DomainDisplay
|
||||||
{
|
{
|
||||||
domain: crate::Domain,
|
domain: crate::Domain,
|
||||||
@@ -13,7 +16,7 @@ pub(crate) fn display_domain(domain: crate::Domain) -> DomainDisplay
|
|||||||
|
|
||||||
impl std::fmt::Debug for DomainDisplay
|
impl std::fmt::Debug for DomainDisplay
|
||||||
{
|
{
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
let domain_name = match self.domain
|
let domain_name = match self.domain
|
||||||
{
|
{
|
||||||
@@ -21,49 +24,34 @@ impl std::fmt::Debug for DomainDisplay
|
|||||||
crate::Domain::Program => "object",
|
crate::Domain::Program => "object",
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(format, "{}", domain_name)
|
write!(formatter, "{}", domain_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for DomainDisplay
|
impl std::fmt::Display for DomainDisplay
|
||||||
{
|
{
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
write!(format, "{:?}", &self)
|
write!(formatter, "{:?}", &self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct FunctionDeclarationDisplay<'a, 'b, C>
|
pub(crate) struct FunctionDeclarationDisplay<'a>(&'a crate::FunctionDeclaration);
|
||||||
where
|
|
||||||
C: crate::traits::InputConstantDeclarationDomain
|
pub(crate) fn display_function_declaration<'a>(function_declaration: &'a crate::FunctionDeclaration)
|
||||||
|
-> FunctionDeclarationDisplay<'a>
|
||||||
{
|
{
|
||||||
function_declaration: &'a std::rc::Rc<foliage::FunctionDeclaration>,
|
FunctionDeclarationDisplay(function_declaration)
|
||||||
context: &'b C,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn display_function_declaration<'a, 'b, C>(
|
impl<'a> std::fmt::Debug for FunctionDeclarationDisplay<'a>
|
||||||
function_declaration: &'a std::rc::Rc<foliage::FunctionDeclaration>, context: &'b C)
|
|
||||||
-> FunctionDeclarationDisplay<'a, 'b, C>
|
|
||||||
where
|
|
||||||
C: crate::traits::InputConstantDeclarationDomain
|
|
||||||
{
|
{
|
||||||
FunctionDeclarationDisplay
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
function_declaration,
|
self.0.display_name(formatter)?;
|
||||||
context,
|
write!(formatter, ":")?;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, C> std::fmt::Debug for FunctionDeclarationDisplay<'a, 'b, C>
|
let domain_identifier = match *self.0.domain.borrow()
|
||||||
where
|
|
||||||
C: crate::traits::InputConstantDeclarationDomain
|
|
||||||
{
|
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
|
||||||
{
|
|
||||||
write!(format, "{}:", self.function_declaration.name)?;
|
|
||||||
|
|
||||||
let domain = self.context.input_constant_declaration_domain(self.function_declaration);
|
|
||||||
let domain_identifier = match domain
|
|
||||||
{
|
{
|
||||||
crate::Domain::Integer => "$int",
|
crate::Domain::Integer => "$int",
|
||||||
crate::Domain::Program => "object",
|
crate::Domain::Program => "object",
|
||||||
@@ -71,37 +59,35 @@ where
|
|||||||
|
|
||||||
let mut separator = "";
|
let mut separator = "";
|
||||||
|
|
||||||
if self.function_declaration.arity > 0
|
if self.0.arity() > 0
|
||||||
{
|
{
|
||||||
write!(format, " (")?;
|
write!(formatter, " (")?;
|
||||||
|
|
||||||
for _ in 0..self.function_declaration.arity
|
for _ in 0..self.0.arity()
|
||||||
{
|
{
|
||||||
write!(format, "{}object", separator)?;
|
write!(formatter, "{}object", separator)?;
|
||||||
separator = " * ";
|
separator = " * ";
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(format, ") >")?;
|
write!(formatter, ") >")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(format, " {}", domain_identifier)
|
write!(formatter, " {}", domain_identifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, C> std::fmt::Display for FunctionDeclarationDisplay<'a, 'b, C>
|
impl<'a> std::fmt::Display for FunctionDeclarationDisplay<'a>
|
||||||
where
|
|
||||||
C: crate::traits::InputConstantDeclarationDomain
|
|
||||||
{
|
{
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
write!(format, "{:?}", &self)
|
write!(formatter, "{:?}", &self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PredicateDeclarationDisplay<'a>(&'a std::rc::Rc<foliage::PredicateDeclaration>);
|
pub(crate) struct PredicateDeclarationDisplay<'a>(&'a crate::PredicateDeclaration);
|
||||||
|
|
||||||
pub(crate) fn display_predicate_declaration<'a>(
|
pub(crate) fn display_predicate_declaration<'a>(
|
||||||
predicate_declaration: &'a std::rc::Rc<foliage::PredicateDeclaration>)
|
predicate_declaration: &'a crate::PredicateDeclaration)
|
||||||
-> PredicateDeclarationDisplay<'a>
|
-> PredicateDeclarationDisplay<'a>
|
||||||
{
|
{
|
||||||
PredicateDeclarationDisplay(predicate_declaration)
|
PredicateDeclarationDisplay(predicate_declaration)
|
||||||
@@ -109,235 +95,142 @@ pub(crate) fn display_predicate_declaration<'a>(
|
|||||||
|
|
||||||
impl<'a> std::fmt::Debug for PredicateDeclarationDisplay<'a>
|
impl<'a> std::fmt::Debug for PredicateDeclarationDisplay<'a>
|
||||||
{
|
{
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
write!(format, "{}:", self.0.name)?;
|
self.0.display_name(formatter)?;
|
||||||
|
write!(formatter, ":")?;
|
||||||
|
|
||||||
let mut separator = "";
|
let mut separator = "";
|
||||||
|
|
||||||
if self.0.arity > 0
|
if self.0.arity() > 0
|
||||||
{
|
{
|
||||||
write!(format, " (")?;
|
write!(formatter, " (")?;
|
||||||
|
|
||||||
for _ in 0..self.0.arity
|
for _ in 0..self.0.arity()
|
||||||
{
|
{
|
||||||
write!(format, "{}object", separator)?;
|
write!(formatter, "{}object", separator)?;
|
||||||
separator = " * ";
|
separator = " * ";
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(format, ") >")?;
|
write!(formatter, ") >")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(format, " $o")
|
write!(formatter, " $o")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> std::fmt::Display for PredicateDeclarationDisplay<'a>
|
impl<'a> std::fmt::Display for PredicateDeclarationDisplay<'a>
|
||||||
{
|
{
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
write!(format, "{:?}", &self)
|
write!(formatter, "{:?}", &self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct VariableDeclarationDisplay<'a, 'b, C>
|
pub(crate) struct TermDisplay<'a>(&'a crate::Term);
|
||||||
where
|
|
||||||
C: crate::traits::VariableDeclarationDomain
|
pub(crate) fn display_term<'a>(term: &'a crate::Term) -> TermDisplay<'a>
|
||||||
+ crate::traits::VariableDeclarationID
|
|
||||||
{
|
{
|
||||||
variable_declaration: &'a std::rc::Rc<foliage::VariableDeclaration>,
|
TermDisplay(term)
|
||||||
context: &'b C,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn display_variable_declaration<'a, 'b, C>(
|
impl<'a> std::fmt::Debug for TermDisplay<'a>
|
||||||
variable_declaration: &'a std::rc::Rc<foliage::VariableDeclaration>, context: &'b C)
|
|
||||||
-> VariableDeclarationDisplay<'a, 'b, C>
|
|
||||||
where
|
|
||||||
C: crate::traits::VariableDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationID
|
|
||||||
{
|
{
|
||||||
VariableDeclarationDisplay
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
variable_declaration,
|
use foliage::*;
|
||||||
context,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, C> std::fmt::Debug for VariableDeclarationDisplay<'a, 'b, C>
|
match &self.0
|
||||||
where
|
|
||||||
C: crate::traits::VariableDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationID
|
|
||||||
{
|
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
|
||||||
{
|
|
||||||
let id = self.context.variable_declaration_id(self.variable_declaration);
|
|
||||||
let domain = self.context.variable_declaration_domain(self.variable_declaration)
|
|
||||||
.expect("unspecified variable domain");
|
|
||||||
|
|
||||||
let prefix = match domain
|
|
||||||
{
|
{
|
||||||
crate::Domain::Integer => "N",
|
Term::Boolean(true) => write!(formatter, "$true"),
|
||||||
crate::Domain::Program => "X",
|
Term::Boolean(false) => write!(formatter, "$false"),
|
||||||
};
|
Term::SpecialInteger(SpecialInteger::Infimum) => write!(formatter, "c__infimum__"),
|
||||||
|
Term::SpecialInteger(SpecialInteger::Supremum) => write!(formatter, "c__supremum__"),
|
||||||
write!(format, "{}{}", prefix, id + 1)
|
Term::Integer(value) => match value.is_negative()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, C> std::fmt::Display for VariableDeclarationDisplay<'a, 'b, C>
|
|
||||||
where
|
|
||||||
C: crate::traits::VariableDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationID
|
|
||||||
{
|
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
|
||||||
{
|
|
||||||
write!(format, "{:?}", &self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct TermDisplay<'a, 'b, C>
|
|
||||||
{
|
|
||||||
term: &'a foliage::Term,
|
|
||||||
context: &'b C,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn display_term<'a, 'b, C>(term: &'a foliage::Term, context: &'b C)
|
|
||||||
-> TermDisplay<'a, 'b, C>
|
|
||||||
where
|
|
||||||
C: crate::traits::VariableDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationID
|
|
||||||
{
|
|
||||||
TermDisplay
|
|
||||||
{
|
|
||||||
term,
|
|
||||||
context,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, C> std::fmt::Debug for TermDisplay<'a, 'b, C>
|
|
||||||
where
|
|
||||||
C: crate::traits::VariableDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationID
|
|
||||||
{
|
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
|
||||||
{
|
|
||||||
let display_variable_declaration = |variable_declaration|
|
|
||||||
display_variable_declaration(variable_declaration, self.context);
|
|
||||||
let display_term = |term| display_term(term, self.context);
|
|
||||||
|
|
||||||
match &self.term
|
|
||||||
{
|
|
||||||
foliage::Term::Boolean(true) => write!(format, "$true"),
|
|
||||||
foliage::Term::Boolean(false) => write!(format, "$false"),
|
|
||||||
foliage::Term::SpecialInteger(foliage::SpecialInteger::Infimum) => write!(format, "c__infimum__"),
|
|
||||||
foliage::Term::SpecialInteger(foliage::SpecialInteger::Supremum) => write!(format, "c__supremum__"),
|
|
||||||
foliage::Term::Integer(value) => match value.is_negative()
|
|
||||||
{
|
{
|
||||||
true => write!(format, "$uminus({})", -value),
|
true => write!(formatter, "$uminus({})", -value),
|
||||||
false => write!(format, "{}", value),
|
false => write!(formatter, "{}", value),
|
||||||
},
|
},
|
||||||
foliage::Term::String(_) => panic!("strings not supported in TPTP"),
|
Term::String(_) => panic!("strings not supported in TPTP"),
|
||||||
foliage::Term::Variable(variable) =>
|
Term::Variable(variable) => variable.declaration.display_name(formatter),
|
||||||
write!(format, "{:?}", display_variable_declaration(&variable.declaration)),
|
Term::Function(function) =>
|
||||||
foliage::Term::Function(function) =>
|
|
||||||
{
|
{
|
||||||
write!(format, "{}", function.declaration.name)?;
|
function.declaration.display_name(formatter)?;
|
||||||
|
|
||||||
assert!(function.declaration.arity == function.arguments.len(),
|
assert!(function.declaration.arity() == function.arguments.len(),
|
||||||
"function has a different number of arguments than declared (expected {}, got {})",
|
"function has a different number of arguments than declared (expected {}, got {})",
|
||||||
function.declaration.arity, function.arguments.len());
|
function.declaration.arity(), function.arguments.len());
|
||||||
|
|
||||||
if function.arguments.len() > 0
|
if function.arguments.len() > 0
|
||||||
{
|
{
|
||||||
write!(format, "{}(", function.declaration.name)?;
|
function.declaration.display_name(formatter)?;
|
||||||
|
write!(formatter, "(")?;
|
||||||
|
|
||||||
let mut separator = "";
|
let mut separator = "";
|
||||||
|
|
||||||
for argument in &function.arguments
|
for argument in &function.arguments
|
||||||
{
|
{
|
||||||
write!(format, "{}{:?}", separator, display_term(&argument))?;
|
write!(formatter, "{}{:?}", separator, display_term(&argument))?;
|
||||||
|
|
||||||
separator = ", ";
|
separator = ", ";
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(format, ")")?;
|
write!(formatter, ")")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
foliage::Term::BinaryOperation(foliage::BinaryOperation{operator: foliage::BinaryOperator::Add, left, right})
|
Term::BinaryOperation(BinaryOperation{operator: BinaryOperator::Add, left, right}) =>
|
||||||
=> write!(format, "$sum({:?}, {:?})", display_term(left), display_term(right)),
|
write!(formatter, "$sum({:?}, {:?})", display_term(left), display_term(right)),
|
||||||
foliage::Term::BinaryOperation(foliage::BinaryOperation{operator: foliage::BinaryOperator::Subtract, left, right})
|
Term::BinaryOperation(BinaryOperation{operator: BinaryOperator::Subtract, left, right})
|
||||||
=> write!(format, "$difference({:?}, {:?})", display_term(left), display_term(right)),
|
=>
|
||||||
foliage::Term::BinaryOperation(foliage::BinaryOperation{operator: foliage::BinaryOperator::Multiply, left, right})
|
write!(formatter, "$difference({:?}, {:?})", display_term(left),
|
||||||
=> write!(format, "$product({:?}, {:?})", display_term(left), display_term(right)),
|
display_term(right)),
|
||||||
foliage::Term::BinaryOperation(foliage::BinaryOperation{operator: foliage::BinaryOperator::Divide, ..})
|
Term::BinaryOperation(BinaryOperation{operator: BinaryOperator::Multiply, left, right})
|
||||||
=> panic!("division not supported with TPTP output"),
|
=>
|
||||||
foliage::Term::BinaryOperation(foliage::BinaryOperation{operator: foliage::BinaryOperator::Modulo, ..})
|
write!(formatter, "$product({:?}, {:?})", display_term(left), display_term(right)),
|
||||||
=> panic!("modulo not supported with TPTP output"),
|
Term::BinaryOperation(BinaryOperation{operator: BinaryOperator::Divide, ..}) =>
|
||||||
foliage::Term::BinaryOperation(foliage::BinaryOperation{operator: foliage::BinaryOperator::Exponentiate, ..})
|
panic!("division not supported with TPTP output"),
|
||||||
=> panic!("exponentiation not supported with TPTP output"),
|
Term::BinaryOperation(BinaryOperation{operator: BinaryOperator::Modulo, ..}) =>
|
||||||
foliage::Term::UnaryOperation(foliage::UnaryOperation{operator: foliage::UnaryOperator::Negative, argument})
|
panic!("modulo not supported with TPTP output"),
|
||||||
=> write!(format, "$uminus({:?})", display_term(argument)),
|
Term::BinaryOperation(BinaryOperation{operator: BinaryOperator::Exponentiate, ..}) =>
|
||||||
foliage::Term::UnaryOperation(foliage::UnaryOperation{operator: foliage::UnaryOperator::AbsoluteValue, ..})
|
panic!("exponentiation not supported with TPTP output"),
|
||||||
=> panic!("absolute value not supported with TPTP output"),
|
Term::UnaryOperation(UnaryOperation{operator: UnaryOperator::Negative, argument}) =>
|
||||||
|
write!(formatter, "$uminus({:?})", display_term(argument)),
|
||||||
|
Term::UnaryOperation(UnaryOperation{operator: UnaryOperator::AbsoluteValue, ..}) =>
|
||||||
|
panic!("absolute value not supported with TPTP output"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, C> std::fmt::Display for TermDisplay<'a, 'b, C>
|
impl<'a> std::fmt::Display for TermDisplay<'a>
|
||||||
where
|
|
||||||
C: crate::traits::VariableDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationID
|
|
||||||
{
|
{
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
write!(format, "{:?}", self)
|
write!(formatter, "{:?}", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct FormulaDisplay<'a, 'b, C>
|
pub(crate) struct FormulaDisplay<'a>(&'a crate::Formula);
|
||||||
|
|
||||||
|
pub(crate) fn display_formula<'a>(formula: &'a crate::Formula) -> FormulaDisplay<'a>
|
||||||
{
|
{
|
||||||
formula: &'a foliage::Formula,
|
FormulaDisplay(formula)
|
||||||
context: &'b C,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn display_formula<'a, 'b, C>(formula: &'a foliage::Formula, context: &'b C)
|
impl<'a> std::fmt::Debug for FormulaDisplay<'a>
|
||||||
-> FormulaDisplay<'a, 'b, C>
|
|
||||||
where
|
|
||||||
C: crate::traits::VariableDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationID
|
|
||||||
{
|
{
|
||||||
FormulaDisplay
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
formula,
|
|
||||||
context,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, C> std::fmt::Debug for FormulaDisplay<'a, 'b, C>
|
|
||||||
where
|
|
||||||
C: crate::traits::InputConstantDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationID
|
|
||||||
{
|
|
||||||
// TODO: rename format to formatter
|
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
|
||||||
{
|
|
||||||
let display_variable_declaration = |variable_declaration|
|
|
||||||
display_variable_declaration(variable_declaration, self.context);
|
|
||||||
let display_term = |term| display_term(term, self.context);
|
|
||||||
let display_formula = |formula| display_formula(formula, self.context);
|
|
||||||
|
|
||||||
let mut display_compare = |left, right, notation, integer_operator_name,
|
let mut display_compare = |left, right, notation, integer_operator_name,
|
||||||
auxiliary_predicate_name| -> std::fmt::Result
|
auxiliary_predicate_name| -> std::fmt::Result
|
||||||
{
|
{
|
||||||
let mut notation = notation;
|
let mut notation = notation;
|
||||||
let mut operation_identifier = integer_operator_name;
|
let mut operation_identifier = integer_operator_name;
|
||||||
|
|
||||||
let is_left_term_arithmetic = crate::is_term_arithmetic(left, self.context)
|
let is_left_term_arithmetic = crate::is_term_arithmetic(left)
|
||||||
.expect("could not determine whether term is arithmetic");
|
.expect("could not determine whether term is arithmetic");
|
||||||
let is_right_term_arithmetic = crate::is_term_arithmetic(right, self.context)
|
let is_right_term_arithmetic = crate::is_term_arithmetic(right)
|
||||||
.expect("could not determine whether term is arithmetic");
|
.expect("could not determine whether term is arithmetic");
|
||||||
|
|
||||||
match (!is_left_term_arithmetic || !is_right_term_arithmetic, auxiliary_predicate_name)
|
match (!is_left_term_arithmetic || !is_right_term_arithmetic, auxiliary_predicate_name)
|
||||||
@@ -352,79 +245,77 @@ where
|
|||||||
|
|
||||||
if notation == crate::OperatorNotation::Prefix
|
if notation == crate::OperatorNotation::Prefix
|
||||||
{
|
{
|
||||||
write!(format, "{}(", operation_identifier)?;
|
write!(formatter, "{}(", operation_identifier)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match is_left_term_arithmetic && !is_right_term_arithmetic
|
match is_left_term_arithmetic && !is_right_term_arithmetic
|
||||||
{
|
{
|
||||||
true => write!(format, "f__integer__({})", display_term(left))?,
|
true => write!(formatter, "f__integer__({})", display_term(left))?,
|
||||||
false => write!(format, "{}", display_term(left))?,
|
false => write!(formatter, "{}", display_term(left))?,
|
||||||
}
|
}
|
||||||
|
|
||||||
match notation
|
match notation
|
||||||
{
|
{
|
||||||
crate::OperatorNotation::Prefix => write!(format, ", ")?,
|
crate::OperatorNotation::Prefix => write!(formatter, ", ")?,
|
||||||
crate::OperatorNotation::Infix => write!(format, " {} ", operation_identifier)?,
|
crate::OperatorNotation::Infix => write!(formatter, " {} ", operation_identifier)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
match is_right_term_arithmetic && !is_left_term_arithmetic
|
match is_right_term_arithmetic && !is_left_term_arithmetic
|
||||||
{
|
{
|
||||||
true => write!(format, "f__integer__({})", display_term(right))?,
|
true => write!(formatter, "f__integer__({})", display_term(right))?,
|
||||||
false => write!(format, "{}", display_term(right))?,
|
false => write!(formatter, "{}", display_term(right))?,
|
||||||
}
|
}
|
||||||
|
|
||||||
if notation == crate::OperatorNotation::Prefix
|
if notation == crate::OperatorNotation::Prefix
|
||||||
{
|
{
|
||||||
write!(format, ")")?;
|
write!(formatter, ")")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
match &self.formula
|
use foliage::*;
|
||||||
|
|
||||||
|
match &self.0
|
||||||
{
|
{
|
||||||
foliage::Formula::Exists(exists) =>
|
// TODO: handle cases with 0 parameters properly
|
||||||
|
Formula::Exists(quantified_formula)
|
||||||
|
| Formula::ForAll(quantified_formula) =>
|
||||||
{
|
{
|
||||||
write!(format, "?[")?;
|
let operator_symbol = match &self.0
|
||||||
|
{
|
||||||
|
Formula::Exists(_) => "?",
|
||||||
|
Formula::ForAll(_) => "!",
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
write!(formatter, "{}[", operator_symbol)?;
|
||||||
|
|
||||||
let mut separator = "";
|
let mut separator = "";
|
||||||
|
|
||||||
for parameter in exists.parameters.iter()
|
for parameter in quantified_formula.parameters.iter()
|
||||||
{
|
{
|
||||||
let parameter_domain = self.context.variable_declaration_domain(parameter)
|
let domain = match parameter.domain()
|
||||||
.expect("unspecified variable domain");
|
{
|
||||||
|
Ok(domain) => domain,
|
||||||
|
Err(_) => unreachable!(
|
||||||
|
"all variable domains should have been checked at this point"),
|
||||||
|
};
|
||||||
|
|
||||||
write!(format, "{}{:?}: {}", separator, display_variable_declaration(parameter),
|
write!(formatter, "{}", separator)?;
|
||||||
display_domain(parameter_domain))?;
|
parameter.display_name(formatter)?;
|
||||||
|
write!(formatter, ": {}", display_domain(domain))?;
|
||||||
|
|
||||||
separator = ", "
|
separator = ", "
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(format, "]: ({:?})", display_formula(&exists.argument))?;
|
write!(formatter, "]: ({:?})", display_formula(&quantified_formula.argument))?;
|
||||||
},
|
},
|
||||||
foliage::Formula::ForAll(for_all) =>
|
Formula::Not(argument) => write!(formatter, "~{:?}", display_formula(argument))?,
|
||||||
|
// TODO: handle cases with < 2 arguments properly
|
||||||
|
Formula::And(arguments) =>
|
||||||
{
|
{
|
||||||
write!(format, "![")?;
|
write!(formatter, "(")?;
|
||||||
|
|
||||||
let mut separator = "";
|
|
||||||
|
|
||||||
for parameter in for_all.parameters.iter()
|
|
||||||
{
|
|
||||||
let parameter_domain = self.context.variable_declaration_domain(parameter)
|
|
||||||
.expect("unspecified variable domain");
|
|
||||||
|
|
||||||
write!(format, "{}{:?}: {}", separator, display_variable_declaration(parameter),
|
|
||||||
display_domain(parameter_domain))?;
|
|
||||||
|
|
||||||
separator = ", "
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(format, "]: ({:?})", display_formula(&for_all.argument))?;
|
|
||||||
},
|
|
||||||
foliage::Formula::Not(argument) => write!(format, "~{:?}", display_formula(argument))?,
|
|
||||||
foliage::Formula::And(arguments) =>
|
|
||||||
{
|
|
||||||
write!(format, "(")?;
|
|
||||||
|
|
||||||
let mut separator = "";
|
let mut separator = "";
|
||||||
|
|
||||||
@@ -432,16 +323,17 @@ where
|
|||||||
|
|
||||||
for argument in arguments
|
for argument in arguments
|
||||||
{
|
{
|
||||||
write!(format, "{}{:?}", separator, display_formula(argument))?;
|
write!(formatter, "{}{:?}", separator, display_formula(argument))?;
|
||||||
|
|
||||||
separator = " & "
|
separator = " & "
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(format, ")")?;
|
write!(formatter, ")")?;
|
||||||
},
|
},
|
||||||
foliage::Formula::Or(arguments) =>
|
// TODO: handle cases with < 2 arguments properly
|
||||||
|
Formula::Or(arguments) =>
|
||||||
{
|
{
|
||||||
write!(format, "(")?;
|
write!(formatter, "(")?;
|
||||||
|
|
||||||
let mut separator = "";
|
let mut separator = "";
|
||||||
|
|
||||||
@@ -449,43 +341,44 @@ where
|
|||||||
|
|
||||||
for argument in arguments
|
for argument in arguments
|
||||||
{
|
{
|
||||||
write!(format, "{}{:?}", separator, display_formula(argument))?;
|
write!(formatter, "{}{:?}", separator, display_formula(argument))?;
|
||||||
|
|
||||||
separator = " | "
|
separator = " | "
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(format, ")")?;
|
write!(formatter, ")")?;
|
||||||
},
|
},
|
||||||
foliage::Formula::Implies(foliage::Implies{antecedent, implication, ..})
|
Formula::Implies(Implies{antecedent, implication, ..}) =>
|
||||||
=> write!(format, "({:?} => {:?})", display_formula(antecedent),
|
write!(formatter, "({:?} => {:?})", display_formula(antecedent),
|
||||||
display_formula(implication))?,
|
display_formula(implication))?,
|
||||||
foliage::Formula::IfAndOnlyIf(arguments) => match arguments.len()
|
// TODO: handle cases with < 2 arguments properly
|
||||||
|
Formula::IfAndOnlyIf(arguments) => match arguments.len()
|
||||||
{
|
{
|
||||||
0 => write!(format, "$true")?,
|
0 => write!(formatter, "$true")?,
|
||||||
_ =>
|
_ =>
|
||||||
{
|
{
|
||||||
let mut separator = "";
|
|
||||||
let parentheses_required = arguments.len() > 2;
|
let parentheses_required = arguments.len() > 2;
|
||||||
|
|
||||||
let mut argument_iterator = arguments.iter().peekable();
|
let mut argument_iterator = arguments.iter().peekable();
|
||||||
|
let mut separator = "";
|
||||||
|
|
||||||
while let Some(argument) = argument_iterator.next()
|
while let Some(argument) = argument_iterator.next()
|
||||||
{
|
{
|
||||||
if let Some(next_argument) = argument_iterator.peek()
|
if let Some(next_argument) = argument_iterator.peek()
|
||||||
{
|
{
|
||||||
write!(format, "{}", separator)?;
|
write!(formatter, "{}", separator)?;
|
||||||
|
|
||||||
if parentheses_required
|
if parentheses_required
|
||||||
{
|
{
|
||||||
write!(format, "(")?;
|
write!(formatter, "(")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(format, "{:?} <=> {:?}", display_formula(argument),
|
write!(formatter, "{:?} <=> {:?}", display_formula(argument),
|
||||||
display_formula(next_argument))?;
|
display_formula(next_argument))?;
|
||||||
|
|
||||||
if parentheses_required
|
if parentheses_required
|
||||||
{
|
{
|
||||||
write!(format, ")")?;
|
write!(formatter, ")")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
separator = " & ";
|
separator = " & ";
|
||||||
@@ -493,58 +386,51 @@ where
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
foliage::Formula::Compare(
|
Formula::Compare(Compare{operator: ComparisonOperator::Less, left, right}) =>
|
||||||
foliage::Compare{operator: foliage::ComparisonOperator::Less, left, right})
|
display_compare(left, right, crate::OperatorNotation::Prefix, "$less",
|
||||||
=> display_compare(left, right, crate::OperatorNotation::Prefix, "$less",
|
|
||||||
Some("p__less__"))?,
|
Some("p__less__"))?,
|
||||||
foliage::Formula::Compare(
|
Formula::Compare(Compare{operator: ComparisonOperator::LessOrEqual, left, right}) =>
|
||||||
foliage::Compare{operator: foliage::ComparisonOperator::LessOrEqual, left, right})
|
display_compare(left, right, crate::OperatorNotation::Prefix, "$lesseq",
|
||||||
=> display_compare(left, right, crate::OperatorNotation::Prefix, "$lesseq",
|
|
||||||
Some("p__less_equal__"))?,
|
Some("p__less_equal__"))?,
|
||||||
foliage::Formula::Compare(
|
Formula::Compare(Compare{operator: ComparisonOperator::Greater, left, right}) =>
|
||||||
foliage::Compare{operator: foliage::ComparisonOperator::Greater, left, right})
|
display_compare(left, right, crate::OperatorNotation::Prefix, "$greater",
|
||||||
=> display_compare(left, right, crate::OperatorNotation::Prefix, "$greater",
|
|
||||||
Some("p__greater__"))?,
|
Some("p__greater__"))?,
|
||||||
foliage::Formula::Compare(
|
Formula::Compare(Compare{operator: ComparisonOperator::GreaterOrEqual, left, right}) =>
|
||||||
foliage::Compare{operator: foliage::ComparisonOperator::GreaterOrEqual, left, right})
|
display_compare(left, right, crate::OperatorNotation::Prefix, "$greatereq",
|
||||||
=> display_compare(left, right, crate::OperatorNotation::Prefix, "$greatereq",
|
|
||||||
Some("p__greater_equal__"))?,
|
Some("p__greater_equal__"))?,
|
||||||
foliage::Formula::Compare(
|
Formula::Compare(Compare{operator: ComparisonOperator::Equal, left, right}) =>
|
||||||
foliage::Compare{operator: foliage::ComparisonOperator::Equal, left, right})
|
display_compare(left, right, crate::OperatorNotation::Infix, "=", None)?,
|
||||||
=> display_compare(left, right, crate::OperatorNotation::Infix, "=", None)?,
|
Formula::Compare(Compare{operator: ComparisonOperator::NotEqual, left, right}) =>
|
||||||
foliage::Formula::Compare(
|
display_compare(left, right, crate::OperatorNotation::Infix, "!=", None)?,
|
||||||
foliage::Compare{operator: foliage::ComparisonOperator::NotEqual, left, right})
|
Formula::Boolean(true) => write!(formatter, "$true")?,
|
||||||
=> display_compare(left, right, crate::OperatorNotation::Infix, "!=", None)?,
|
Formula::Boolean(false) => write!(formatter, "$false")?,
|
||||||
foliage::Formula::Boolean(true) => write!(format, "$true")?,
|
Formula::Predicate(predicate) =>
|
||||||
foliage::Formula::Boolean(false) => write!(format, "$false")?,
|
|
||||||
foliage::Formula::Predicate(predicate) =>
|
|
||||||
{
|
{
|
||||||
write!(format, "{}", predicate.declaration.name)?;
|
predicate.declaration.display_name(formatter)?;
|
||||||
|
|
||||||
if !predicate.arguments.is_empty()
|
if !predicate.arguments.is_empty()
|
||||||
{
|
{
|
||||||
write!(format, "(")?;
|
write!(formatter, "(")?;
|
||||||
|
|
||||||
let mut separator = "";
|
let mut separator = "";
|
||||||
|
|
||||||
for argument in &predicate.arguments
|
for argument in &predicate.arguments
|
||||||
{
|
{
|
||||||
write!(format, "{}", separator)?;
|
write!(formatter, "{}", separator)?;
|
||||||
|
|
||||||
let is_argument_arithmetic =
|
let is_argument_arithmetic = crate::is_term_arithmetic(argument)
|
||||||
crate::is_term_arithmetic(argument, self.context)
|
.expect("could not determine whether term is arithmetic");
|
||||||
.expect("could not determine whether term is arithmetic");
|
|
||||||
|
|
||||||
match is_argument_arithmetic
|
match is_argument_arithmetic
|
||||||
{
|
{
|
||||||
true => write!(format, "f__integer__({})", display_term(argument))?,
|
true => write!(formatter, "f__integer__({})", display_term(argument))?,
|
||||||
false => write!(format, "{}", display_term(argument))?,
|
false => write!(formatter, "{}", display_term(argument))?,
|
||||||
}
|
}
|
||||||
|
|
||||||
separator = ", "
|
separator = ", "
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(format, ")")?;
|
write!(formatter, ")")?;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -553,14 +439,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, C> std::fmt::Display for FormulaDisplay<'a, 'b, C>
|
impl<'a> std::fmt::Display for FormulaDisplay<'a>
|
||||||
where
|
|
||||||
C: crate::traits::InputConstantDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationID
|
|
||||||
{
|
{
|
||||||
fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
{
|
{
|
||||||
write!(format, "{:?}", self)
|
write!(formatter, "{:?}", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1017
src/problem.rs
1017
src/problem.rs
File diff suppressed because it is too large
Load Diff
85
src/problem/proof_direction.rs
Normal file
85
src/problem/proof_direction.rs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||||
|
pub enum ProofDirection
|
||||||
|
{
|
||||||
|
Forward,
|
||||||
|
Backward,
|
||||||
|
Both,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProofDirection
|
||||||
|
{
|
||||||
|
pub fn requires_forward_proof(&self) -> bool
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::Forward
|
||||||
|
| Self::Both => true,
|
||||||
|
Self::Backward => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn requires_backward_proof(&self) -> bool
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::Forward => false,
|
||||||
|
Self::Backward
|
||||||
|
| Self::Both => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for ProofDirection
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
ProofDirection::Forward => write!(formatter, "forward"),
|
||||||
|
ProofDirection::Backward => write!(formatter, "backward"),
|
||||||
|
ProofDirection::Both => write!(formatter, "both"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ProofDirection
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
write!(formatter, "{:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InvalidProofDirectionError;
|
||||||
|
|
||||||
|
impl std::fmt::Debug for InvalidProofDirectionError
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
write!(formatter, "invalid proof direction")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for InvalidProofDirectionError
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
write!(formatter, "{:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for ProofDirection
|
||||||
|
{
|
||||||
|
type Err = InvalidProofDirectionError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err>
|
||||||
|
{
|
||||||
|
match s
|
||||||
|
{
|
||||||
|
"forward" => Ok(ProofDirection::Forward),
|
||||||
|
"backward" => Ok(ProofDirection::Backward),
|
||||||
|
"both" => Ok(ProofDirection::Both),
|
||||||
|
_ => Err(InvalidProofDirectionError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
src/problem/section_kind.rs
Normal file
35
src/problem/section_kind.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// TODO: remove if possible
|
||||||
|
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
|
pub enum SectionKind
|
||||||
|
{
|
||||||
|
Axioms,
|
||||||
|
Assumptions,
|
||||||
|
Lemmas,
|
||||||
|
CompletedDefinitions,
|
||||||
|
IntegrityConstraints,
|
||||||
|
Specs,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for SectionKind
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::CompletedDefinitions => write!(formatter, "completed definition"),
|
||||||
|
Self::IntegrityConstraints => write!(formatter, "integrity constraint"),
|
||||||
|
Self::Axioms => write!(formatter, "axiom"),
|
||||||
|
Self::Assumptions => write!(formatter, "assumption"),
|
||||||
|
Self::Lemmas => write!(formatter, "lemma"),
|
||||||
|
Self::Specs => write!(formatter, "spec"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for SectionKind
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
write!(formatter, "{:?}", self)
|
||||||
|
}
|
||||||
|
}
|
77
src/problem/statement.rs
Normal file
77
src/problem/statement.rs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
use super::ProofDirection;
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
pub(crate) enum StatementKind
|
||||||
|
{
|
||||||
|
Axiom,
|
||||||
|
Assumption,
|
||||||
|
CompletedDefinition(std::rc::Rc<crate::PredicateDeclaration>),
|
||||||
|
IntegrityConstraint,
|
||||||
|
Lemma(ProofDirection),
|
||||||
|
Spec,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for StatementKind
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Self::Axiom => write!(formatter, "axiom"),
|
||||||
|
Self::Assumption => write!(formatter, "assumption"),
|
||||||
|
Self::CompletedDefinition(ref predicate_declaration) =>
|
||||||
|
write!(formatter, "completed definition of {}", predicate_declaration.declaration),
|
||||||
|
Self::IntegrityConstraint => write!(formatter, "integrity constraint"),
|
||||||
|
Self::Lemma(_) => write!(formatter, "lemma"),
|
||||||
|
Self::Spec => write!(formatter, "spec"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for StatementKind
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||||
|
{
|
||||||
|
write!(formatter, "{:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub(crate) enum ProofStatus
|
||||||
|
{
|
||||||
|
AssumedProven,
|
||||||
|
Proven,
|
||||||
|
NotProven,
|
||||||
|
Disproven,
|
||||||
|
ToProveNow,
|
||||||
|
ToProveLater,
|
||||||
|
Ignored,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Statement
|
||||||
|
{
|
||||||
|
pub kind: StatementKind,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub formula: crate::Formula,
|
||||||
|
pub proof_status: ProofStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement
|
||||||
|
{
|
||||||
|
pub fn new(kind: StatementKind, formula: crate::Formula) -> Self
|
||||||
|
{
|
||||||
|
Self
|
||||||
|
{
|
||||||
|
kind,
|
||||||
|
name: None,
|
||||||
|
formula,
|
||||||
|
proof_status: ProofStatus::ToProveLater,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_name(mut self, name: String) -> Self
|
||||||
|
{
|
||||||
|
self.name = Some(name);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
269
src/simplify.rs
Normal file
269
src/simplify.rs
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
enum SimplificationResult
|
||||||
|
{
|
||||||
|
Simplified,
|
||||||
|
NotSimplified,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimplificationResult
|
||||||
|
{
|
||||||
|
fn or(&self, other: SimplificationResult) -> SimplificationResult
|
||||||
|
{
|
||||||
|
match (self, other)
|
||||||
|
{
|
||||||
|
(SimplificationResult::NotSimplified, SimplificationResult::NotSimplified)
|
||||||
|
=> SimplificationResult::NotSimplified,
|
||||||
|
_ => SimplificationResult::Simplified,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_unnecessary_exists_parameters(formula: &mut crate::Formula)
|
||||||
|
-> Result<SimplificationResult, crate::Error>
|
||||||
|
{
|
||||||
|
use crate::{Formula, Term};
|
||||||
|
|
||||||
|
match formula
|
||||||
|
{
|
||||||
|
Formula::And(ref mut arguments)
|
||||||
|
| Formula::IfAndOnlyIf(ref mut arguments)
|
||||||
|
| Formula::Or(ref mut arguments) =>
|
||||||
|
{
|
||||||
|
let mut simplification_result = SimplificationResult::NotSimplified;
|
||||||
|
|
||||||
|
for argument in arguments
|
||||||
|
{
|
||||||
|
simplification_result = simplification_result.or(
|
||||||
|
remove_unnecessary_exists_parameters(argument)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(simplification_result)
|
||||||
|
},
|
||||||
|
Formula::Boolean(_)
|
||||||
|
| Formula::Compare(_)
|
||||||
|
| Formula::Predicate(_) => Ok(SimplificationResult::NotSimplified),
|
||||||
|
Formula::Exists(ref mut quantified_formula) =>
|
||||||
|
{
|
||||||
|
let mut simplification_result =
|
||||||
|
remove_unnecessary_exists_parameters(&mut quantified_formula.argument)?;
|
||||||
|
|
||||||
|
let arguments = match *quantified_formula.argument
|
||||||
|
{
|
||||||
|
Formula::And(ref mut arguments) => arguments,
|
||||||
|
_ => return remove_unnecessary_exists_parameters(&mut quantified_formula.argument),
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: do not copy parameters, use std::vec::Vec::retain instead
|
||||||
|
quantified_formula.parameters =
|
||||||
|
std::rc::Rc::new(quantified_formula.parameters.iter().filter_map(
|
||||||
|
|parameter|
|
||||||
|
{
|
||||||
|
let assignment = arguments.iter().enumerate().find_map(
|
||||||
|
|(argument_index, argument)|
|
||||||
|
{
|
||||||
|
let (left, right) = match argument
|
||||||
|
{
|
||||||
|
Formula::Compare(foliage::Compare{
|
||||||
|
operator: foliage::ComparisonOperator::Equal, ref left,
|
||||||
|
ref right})
|
||||||
|
=> (left, right),
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let assigned_term = match (&**left, &**right)
|
||||||
|
{
|
||||||
|
(Term::Variable(ref variable), right)
|
||||||
|
if variable.declaration == *parameter =>
|
||||||
|
right,
|
||||||
|
(left, Term::Variable(ref variable))
|
||||||
|
if variable.declaration == *parameter =>
|
||||||
|
left,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let parameter_domain = match parameter.domain()
|
||||||
|
{
|
||||||
|
Ok(domain) => domain,
|
||||||
|
Err(_) =>
|
||||||
|
unreachable!("all variable domains should be assigned at this point"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_parameter_integer =
|
||||||
|
parameter_domain == crate::Domain::Integer;
|
||||||
|
|
||||||
|
let is_assigned_term_arithmetic =
|
||||||
|
match crate::is_term_arithmetic(assigned_term)
|
||||||
|
{
|
||||||
|
Ok(is_term_arithmetic) => is_term_arithmetic,
|
||||||
|
Err(error) => return Some(Err(error)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_assignment_narrowing = is_parameter_integer
|
||||||
|
&& !is_assigned_term_arithmetic;
|
||||||
|
|
||||||
|
if crate::term_contains_variable(assigned_term, parameter)
|
||||||
|
|| is_assignment_narrowing
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: avoid copy
|
||||||
|
Some(Ok((argument_index, crate::copy_term(assigned_term))))
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(assignment) = assignment
|
||||||
|
{
|
||||||
|
let (assignment_index, assigned_term) = match assignment
|
||||||
|
{
|
||||||
|
Err(error) => return Some(Err(error)),
|
||||||
|
Ok(assignment) => assignment,
|
||||||
|
};
|
||||||
|
|
||||||
|
arguments.remove(assignment_index);
|
||||||
|
|
||||||
|
for argument in arguments.iter_mut()
|
||||||
|
{
|
||||||
|
crate::replace_variable_in_formula_with_term(argument, parameter,
|
||||||
|
&assigned_term);
|
||||||
|
}
|
||||||
|
|
||||||
|
simplification_result = SimplificationResult::Simplified;
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Ok(std::rc::Rc::clone(parameter)))
|
||||||
|
})
|
||||||
|
.collect::<Result<_, _>>()?);
|
||||||
|
|
||||||
|
Ok(simplification_result)
|
||||||
|
}
|
||||||
|
Formula::ForAll(ref mut quantified_formula) =>
|
||||||
|
remove_unnecessary_exists_parameters(&mut quantified_formula.argument),
|
||||||
|
Formula::Implies(ref mut implies) =>
|
||||||
|
remove_unnecessary_exists_parameters(&mut implies.antecedent)
|
||||||
|
.or(remove_unnecessary_exists_parameters(&mut implies.implication)),
|
||||||
|
Formula::Not(ref mut argument) =>
|
||||||
|
remove_unnecessary_exists_parameters(argument),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simplify_quantified_formulas_without_parameters(formula: &mut crate::Formula)
|
||||||
|
-> SimplificationResult
|
||||||
|
{
|
||||||
|
use crate::Formula;
|
||||||
|
|
||||||
|
match formula
|
||||||
|
{
|
||||||
|
Formula::And(arguments)
|
||||||
|
| Formula::IfAndOnlyIf(arguments)
|
||||||
|
| Formula::Or(arguments) =>
|
||||||
|
{
|
||||||
|
let mut simplification_result = SimplificationResult::NotSimplified;
|
||||||
|
|
||||||
|
for mut argument in arguments
|
||||||
|
{
|
||||||
|
simplification_result = simplification_result.or(
|
||||||
|
simplify_quantified_formulas_without_parameters(&mut argument));
|
||||||
|
}
|
||||||
|
|
||||||
|
simplification_result
|
||||||
|
},
|
||||||
|
Formula::Boolean(_)
|
||||||
|
| Formula::Compare(_)
|
||||||
|
| Formula::Predicate(_) => SimplificationResult::NotSimplified,
|
||||||
|
Formula::Exists(quantified_formula)
|
||||||
|
| Formula::ForAll(quantified_formula) =>
|
||||||
|
{
|
||||||
|
if quantified_formula.parameters.is_empty()
|
||||||
|
{
|
||||||
|
// TODO: remove workaround
|
||||||
|
let mut argument = crate::Formula::false_();
|
||||||
|
std::mem::swap(&mut argument, &mut quantified_formula.argument);
|
||||||
|
|
||||||
|
*formula = argument;
|
||||||
|
|
||||||
|
return SimplificationResult::Simplified;
|
||||||
|
}
|
||||||
|
|
||||||
|
simplify_quantified_formulas_without_parameters(&mut quantified_formula.argument)
|
||||||
|
},
|
||||||
|
Formula::Implies(ref mut implies) =>
|
||||||
|
simplify_quantified_formulas_without_parameters(&mut implies.antecedent)
|
||||||
|
.or(simplify_quantified_formulas_without_parameters(&mut implies.implication)),
|
||||||
|
Formula::Not(ref mut argument) =>
|
||||||
|
simplify_quantified_formulas_without_parameters(argument),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simplify_trivial_n_ary_formulas(formula: &mut crate::Formula) -> SimplificationResult
|
||||||
|
{
|
||||||
|
use crate::Formula;
|
||||||
|
|
||||||
|
match formula
|
||||||
|
{
|
||||||
|
Formula::And(arguments)
|
||||||
|
| Formula::IfAndOnlyIf(arguments) if arguments.is_empty() =>
|
||||||
|
{
|
||||||
|
*formula = crate::Formula::true_();
|
||||||
|
|
||||||
|
return SimplificationResult::Simplified;
|
||||||
|
},
|
||||||
|
| Formula::Or(arguments) if arguments.is_empty() =>
|
||||||
|
{
|
||||||
|
*formula = crate::Formula::false_();
|
||||||
|
|
||||||
|
return SimplificationResult::Simplified;
|
||||||
|
},
|
||||||
|
Formula::And(arguments)
|
||||||
|
| Formula::IfAndOnlyIf(arguments)
|
||||||
|
| Formula::Or(arguments) =>
|
||||||
|
{
|
||||||
|
if arguments.len() == 1
|
||||||
|
{
|
||||||
|
*formula = arguments.remove(0);
|
||||||
|
|
||||||
|
return SimplificationResult::Simplified;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut simplification_result = SimplificationResult::NotSimplified;
|
||||||
|
|
||||||
|
for mut argument in arguments
|
||||||
|
{
|
||||||
|
simplification_result = simplification_result.or(
|
||||||
|
simplify_trivial_n_ary_formulas(&mut argument));
|
||||||
|
}
|
||||||
|
|
||||||
|
simplification_result
|
||||||
|
},
|
||||||
|
Formula::Boolean(_)
|
||||||
|
| Formula::Compare(_)
|
||||||
|
| Formula::Predicate(_) => SimplificationResult::NotSimplified,
|
||||||
|
Formula::Exists(ref mut quantified_formula)
|
||||||
|
| Formula::ForAll(ref mut quantified_formula) =>
|
||||||
|
simplify_trivial_n_ary_formulas(&mut quantified_formula.argument),
|
||||||
|
Formula::Implies(ref mut implies) =>
|
||||||
|
simplify_trivial_n_ary_formulas(&mut implies.antecedent)
|
||||||
|
.or(simplify_trivial_n_ary_formulas(&mut implies.implication)),
|
||||||
|
Formula::Not(ref mut argument) =>
|
||||||
|
simplify_trivial_n_ary_formulas(argument),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn simplify(formula: &mut crate::Formula) -> Result<(), crate::Error>
|
||||||
|
{
|
||||||
|
loop
|
||||||
|
{
|
||||||
|
if remove_unnecessary_exists_parameters(formula)? == SimplificationResult::Simplified
|
||||||
|
|| simplify_quantified_formulas_without_parameters(formula)
|
||||||
|
== SimplificationResult::Simplified
|
||||||
|
|| simplify_trivial_n_ary_formulas(formula) == SimplificationResult::Simplified
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@@ -1,36 +0,0 @@
|
|||||||
/*#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
|
||||||
pub enum ProofDirection
|
|
||||||
{
|
|
||||||
Forward,
|
|
||||||
Backward,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq)]
|
|
||||||
pub enum CompletionTarget
|
|
||||||
{
|
|
||||||
Predicate(std::rc::Rc<foliage::PredicateDeclaration>),
|
|
||||||
Constraint,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CompletionFormula
|
|
||||||
{
|
|
||||||
pub target: CompletionTarget,
|
|
||||||
pub formula: foliage::Formula,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Lemma
|
|
||||||
{
|
|
||||||
pub direction: Option<ProofDirection>,
|
|
||||||
pub formula: foliage::Formula,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Specification
|
|
||||||
{
|
|
||||||
pub axioms: foliage::Formulas,
|
|
||||||
pub lemmas: Vec<Lemma>,
|
|
||||||
pub assumptions: foliage::Formulas,
|
|
||||||
pub assertions: foliage::Formulas,
|
|
||||||
|
|
||||||
pub input_constants: foliage::FunctionDeclarations,
|
|
||||||
pub input_predicates: foliage::PredicateDeclarations,
|
|
||||||
}*/
|
|
@@ -1,23 +0,0 @@
|
|||||||
pub(crate) trait InputConstantDeclarationDomain
|
|
||||||
{
|
|
||||||
fn input_constant_declaration_domain(&self,
|
|
||||||
declaration: &std::rc::Rc<foliage::FunctionDeclaration>) -> crate::Domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait AssignVariableDeclarationDomain
|
|
||||||
{
|
|
||||||
fn assign_variable_declaration_domain(&self,
|
|
||||||
variable_declaration: &std::rc::Rc<foliage::VariableDeclaration>, domain: crate::Domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait VariableDeclarationDomain
|
|
||||||
{
|
|
||||||
fn variable_declaration_domain(&self,
|
|
||||||
variable_declaration: &std::rc::Rc<foliage::VariableDeclaration>) -> Option<crate::Domain>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait VariableDeclarationID
|
|
||||||
{
|
|
||||||
fn variable_declaration_id(&self,
|
|
||||||
variable_declaration: &std::rc::Rc<foliage::VariableDeclaration>) -> usize;
|
|
||||||
}
|
|
@@ -1,19 +1,18 @@
|
|||||||
pub(crate) fn choose_value_in_primitive(term: Box<foliage::Term>,
|
pub(crate) fn choose_value_in_primitive(term: Box<crate::Term>,
|
||||||
variable_declaration: std::rc::Rc<foliage::VariableDeclaration>)
|
variable_declaration: std::rc::Rc<crate::VariableDeclaration>)
|
||||||
-> foliage::Formula
|
-> crate::Formula
|
||||||
{
|
{
|
||||||
let variable = foliage::Term::variable(variable_declaration);
|
let variable = crate::Term::variable(variable_declaration);
|
||||||
|
|
||||||
foliage::Formula::equal(Box::new(variable), term)
|
crate::Formula::equal(Box::new(variable), term)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn choose_value_in_term<C>(term: &clingo::ast::Term,
|
pub(crate) fn choose_value_in_term<C>(term: &clingo::ast::Term,
|
||||||
variable_declaration: std::rc::Rc<foliage::VariableDeclaration>, context: &C,
|
variable_declaration: std::rc::Rc<crate::VariableDeclaration>, context: &C,
|
||||||
variable_declaration_stack: &foliage::VariableDeclarationStackLayer)
|
variable_declaration_stack: &crate::VariableDeclarationStackLayer)
|
||||||
-> Result<foliage::Formula, crate::Error>
|
-> Result<crate::Formula, crate::Error>
|
||||||
where
|
where
|
||||||
C: foliage::FindOrCreateFunctionDeclaration
|
C: foliage::FindOrCreateFunctionDeclaration<crate::FoliageFlavor>,
|
||||||
+ crate::traits::AssignVariableDeclarationDomain
|
|
||||||
{
|
{
|
||||||
match term.term_type()
|
match term.term_type()
|
||||||
{
|
{
|
||||||
@@ -21,15 +20,15 @@ where
|
|||||||
.map_err(|error| crate::Error::new_logic("clingo error").with(error))?
|
.map_err(|error| crate::Error::new_logic("clingo error").with(error))?
|
||||||
{
|
{
|
||||||
clingo::SymbolType::Number => Ok(choose_value_in_primitive(
|
clingo::SymbolType::Number => Ok(choose_value_in_primitive(
|
||||||
Box::new(foliage::Term::integer(symbol.number()
|
Box::new(crate::Term::integer(symbol.number()
|
||||||
.map_err(|error| crate::Error::new_logic("clingo error").with(error))?)),
|
.map_err(|error| crate::Error::new_logic("clingo error").with(error))?)),
|
||||||
variable_declaration)),
|
variable_declaration)),
|
||||||
clingo::SymbolType::Infimum => Ok(choose_value_in_primitive(
|
clingo::SymbolType::Infimum => Ok(choose_value_in_primitive(
|
||||||
Box::new(foliage::Term::infimum()), variable_declaration)),
|
Box::new(crate::Term::infimum()), variable_declaration)),
|
||||||
clingo::SymbolType::Supremum => Ok(choose_value_in_primitive(
|
clingo::SymbolType::Supremum => Ok(choose_value_in_primitive(
|
||||||
Box::new(foliage::Term::supremum()), variable_declaration)),
|
Box::new(crate::Term::supremum()), variable_declaration)),
|
||||||
clingo::SymbolType::String => Ok(choose_value_in_primitive(
|
clingo::SymbolType::String => Ok(choose_value_in_primitive(
|
||||||
Box::new(foliage::Term::string(symbol.string()
|
Box::new(crate::Term::string(symbol.string()
|
||||||
.map_err(|error| crate::Error::new_logic("clingo error").with(error))?
|
.map_err(|error| crate::Error::new_logic("clingo error").with(error))?
|
||||||
.to_string())),
|
.to_string())),
|
||||||
variable_declaration)),
|
variable_declaration)),
|
||||||
@@ -51,7 +50,7 @@ where
|
|||||||
|
|
||||||
let constant_declaration =
|
let constant_declaration =
|
||||||
context.find_or_create_function_declaration(constant_name, 0);
|
context.find_or_create_function_declaration(constant_name, 0);
|
||||||
let function = foliage::Term::function(constant_declaration, vec![]);
|
let function = crate::Term::function(constant_declaration, vec![]);
|
||||||
|
|
||||||
Ok(choose_value_in_primitive(Box::new(function), variable_declaration))
|
Ok(choose_value_in_primitive(Box::new(function), variable_declaration))
|
||||||
}
|
}
|
||||||
@@ -60,14 +59,14 @@ where
|
|||||||
{
|
{
|
||||||
let other_variable_declaration = match variable_name
|
let other_variable_declaration = match variable_name
|
||||||
{
|
{
|
||||||
// TODO: check
|
|
||||||
// Every occurrence of anonymous variables is treated as if it introduced a fresh
|
// Every occurrence of anonymous variables is treated as if it introduced a fresh
|
||||||
// variable declaration
|
// variable declaration
|
||||||
"_" => variable_declaration_stack.free_variable_declarations_do_mut(
|
"_" => variable_declaration_stack.free_variable_declarations_do_mut(
|
||||||
|free_variable_declarations|
|
|free_variable_declarations|
|
||||||
{
|
{
|
||||||
|
// TODO: check domain type
|
||||||
let variable_declaration = std::rc::Rc::new(
|
let variable_declaration = std::rc::Rc::new(
|
||||||
foliage::VariableDeclaration::new("_".to_owned()));
|
crate::VariableDeclaration::new_generated(crate::Domain::Program));
|
||||||
|
|
||||||
free_variable_declarations.push(std::rc::Rc::clone(&variable_declaration));
|
free_variable_declarations.push(std::rc::Rc::clone(&variable_declaration));
|
||||||
|
|
||||||
@@ -75,9 +74,7 @@ where
|
|||||||
}),
|
}),
|
||||||
_ => variable_declaration_stack.find_or_create(variable_name),
|
_ => variable_declaration_stack.find_or_create(variable_name),
|
||||||
};
|
};
|
||||||
context.assign_variable_declaration_domain(&other_variable_declaration,
|
let other_variable = crate::Term::variable(other_variable_declaration);
|
||||||
crate::Domain::Program);
|
|
||||||
let other_variable = foliage::Term::variable(other_variable_declaration);
|
|
||||||
|
|
||||||
Ok(choose_value_in_primitive(Box::new(other_variable), variable_declaration))
|
Ok(choose_value_in_primitive(Box::new(other_variable), variable_declaration))
|
||||||
},
|
},
|
||||||
@@ -92,26 +89,21 @@ where
|
|||||||
| foliage::BinaryOperator::Multiply
|
| foliage::BinaryOperator::Multiply
|
||||||
=>
|
=>
|
||||||
{
|
{
|
||||||
let parameters = (0..2).map(|_|
|
let parameters = (0..2).map(
|
||||||
{
|
|_| std::rc::Rc::new(crate::VariableDeclaration::new_generated(
|
||||||
let variable_declaration = std::rc::Rc::new(
|
crate::Domain::Integer)))
|
||||||
foliage::VariableDeclaration::new("<anonymous>".to_string()));
|
.collect::<crate::VariableDeclarations>();
|
||||||
context.assign_variable_declaration_domain(&variable_declaration,
|
|
||||||
crate::Domain::Integer);
|
|
||||||
variable_declaration
|
|
||||||
})
|
|
||||||
.collect::<foliage::VariableDeclarations>();
|
|
||||||
let parameters = std::rc::Rc::new(parameters);
|
let parameters = std::rc::Rc::new(parameters);
|
||||||
|
|
||||||
let parameter_1 = ¶meters[0];
|
let parameter_1 = ¶meters[0];
|
||||||
let parameter_2 = ¶meters[1];
|
let parameter_2 = ¶meters[1];
|
||||||
|
|
||||||
let translated_binary_operation = foliage::Term::binary_operation(operator,
|
let translated_binary_operation = crate::Term::binary_operation(operator,
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(¶meter_1))),
|
Box::new(crate::Term::variable(std::rc::Rc::clone(¶meter_1))),
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(¶meter_2))));
|
Box::new(crate::Term::variable(std::rc::Rc::clone(¶meter_2))));
|
||||||
|
|
||||||
let equals = foliage::Formula::equal(
|
let equals = crate::Formula::equal(
|
||||||
Box::new(foliage::Term::variable(variable_declaration)),
|
Box::new(crate::Term::variable(variable_declaration)),
|
||||||
Box::new(translated_binary_operation));
|
Box::new(translated_binary_operation));
|
||||||
|
|
||||||
let choose_value_from_left_argument = choose_value_in_term(
|
let choose_value_from_left_argument = choose_value_in_term(
|
||||||
@@ -122,24 +114,19 @@ where
|
|||||||
binary_operation.right(), std::rc::Rc::clone(¶meter_2), context,
|
binary_operation.right(), std::rc::Rc::clone(¶meter_2), context,
|
||||||
variable_declaration_stack)?;
|
variable_declaration_stack)?;
|
||||||
|
|
||||||
let and = foliage::Formula::And(vec![equals, choose_value_from_left_argument,
|
let and = crate::Formula::And(vec![equals, choose_value_from_left_argument,
|
||||||
choose_value_from_right_argument]);
|
choose_value_from_right_argument]);
|
||||||
|
|
||||||
Ok(foliage::Formula::exists(parameters, Box::new(and)))
|
Ok(crate::Formula::exists(parameters, Box::new(and)))
|
||||||
},
|
},
|
||||||
foliage::BinaryOperator::Divide
|
foliage::BinaryOperator::Divide
|
||||||
| foliage::BinaryOperator::Modulo
|
| foliage::BinaryOperator::Modulo
|
||||||
=>
|
=>
|
||||||
{
|
{
|
||||||
let parameters = (0..4).map(|_|
|
let parameters = (0..4).map(
|
||||||
{
|
|_| std::rc::Rc::new(crate::VariableDeclaration::new_generated(
|
||||||
let variable_declaration = std::rc::Rc::new(
|
crate::Domain::Integer)))
|
||||||
foliage::VariableDeclaration::new("<anonymous>".to_string()));
|
.collect::<crate::VariableDeclarations>();
|
||||||
context.assign_variable_declaration_domain(&variable_declaration,
|
|
||||||
crate::Domain::Integer);
|
|
||||||
variable_declaration
|
|
||||||
})
|
|
||||||
.collect::<foliage::VariableDeclarations>();
|
|
||||||
let parameters = std::rc::Rc::new(parameters);
|
let parameters = std::rc::Rc::new(parameters);
|
||||||
|
|
||||||
let parameter_i = ¶meters[0];
|
let parameter_i = ¶meters[0];
|
||||||
@@ -147,43 +134,43 @@ where
|
|||||||
let parameter_q = ¶meters[2];
|
let parameter_q = ¶meters[2];
|
||||||
let parameter_r = ¶meters[3];
|
let parameter_r = ¶meters[3];
|
||||||
|
|
||||||
let j_times_q = foliage::Term::multiply(
|
let j_times_q = crate::Term::multiply(
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_j))),
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_j))),
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_q))));
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_q))));
|
||||||
|
|
||||||
let j_times_q_plus_r = foliage::Term::add(Box::new(j_times_q),
|
let j_times_q_plus_r = crate::Term::add(Box::new(j_times_q),
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_r))));
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_r))));
|
||||||
|
|
||||||
let i_equals_j_times_q_plus_r = foliage::Formula::equal(
|
let i_equals_j_times_q_plus_r = crate::Formula::equal(
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_j))),
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_i))),
|
||||||
Box::new(j_times_q_plus_r));
|
Box::new(j_times_q_plus_r));
|
||||||
|
|
||||||
let choose_i_in_t1 = choose_value_in_term(binary_operation.left(),
|
let choose_i_in_t1 = choose_value_in_term(binary_operation.left(),
|
||||||
std::rc::Rc::clone(parameter_i), context, variable_declaration_stack)?;
|
std::rc::Rc::clone(parameter_i), context, variable_declaration_stack)?;
|
||||||
|
|
||||||
let choose_i_in_t2 = choose_value_in_term(binary_operation.left(),
|
let choose_j_in_t2 = choose_value_in_term(binary_operation.right(),
|
||||||
std::rc::Rc::clone(parameter_j), context, variable_declaration_stack)?;
|
std::rc::Rc::clone(parameter_j), context, variable_declaration_stack)?;
|
||||||
|
|
||||||
let j_not_equal_to_0 = foliage::Formula::not_equal(
|
let j_not_equal_to_0 = crate::Formula::not_equal(
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_j))),
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_j))),
|
||||||
Box::new(foliage::Term::integer(0)));
|
Box::new(crate::Term::integer(0)));
|
||||||
|
|
||||||
let r_greater_or_equal_to_0 = foliage::Formula::greater_or_equal(
|
let r_greater_or_equal_to_0 = crate::Formula::greater_or_equal(
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_r))),
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_r))),
|
||||||
Box::new(foliage::Term::integer(0)));
|
Box::new(crate::Term::integer(0)));
|
||||||
|
|
||||||
let r_less_than_q = foliage::Formula::less(
|
let r_less_than_q = crate::Formula::less(
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_r))),
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_r))),
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_q))));
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_q))));
|
||||||
|
|
||||||
let z_equal_to_q = foliage::Formula::equal(
|
let z_equal_to_q = crate::Formula::equal(
|
||||||
Box::new(
|
Box::new(
|
||||||
foliage::Term::variable(std::rc::Rc::clone(&variable_declaration))),
|
crate::Term::variable(std::rc::Rc::clone(&variable_declaration))),
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_q))));
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_q))));
|
||||||
|
|
||||||
let z_equal_to_r = foliage::Formula::equal(
|
let z_equal_to_r = crate::Formula::equal(
|
||||||
Box::new(foliage::Term::variable(variable_declaration)),
|
Box::new(crate::Term::variable(variable_declaration)),
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_r))));
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_r))));
|
||||||
|
|
||||||
let last_argument = match operator
|
let last_argument = match operator
|
||||||
{
|
{
|
||||||
@@ -192,11 +179,11 @@ where
|
|||||||
_ => return Err(crate::Error::new_logic("unreachable code")),
|
_ => return Err(crate::Error::new_logic("unreachable code")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let and = foliage::Formula::and(vec![i_equals_j_times_q_plus_r, choose_i_in_t1,
|
let and = crate::Formula::and(vec![i_equals_j_times_q_plus_r, choose_i_in_t1,
|
||||||
choose_i_in_t2, j_not_equal_to_0, r_greater_or_equal_to_0, r_less_than_q,
|
choose_j_in_t2, j_not_equal_to_0, r_greater_or_equal_to_0, r_less_than_q,
|
||||||
last_argument]);
|
last_argument]);
|
||||||
|
|
||||||
Ok(foliage::Formula::exists(parameters, Box::new(and)))
|
Ok(crate::Formula::exists(parameters, Box::new(and)))
|
||||||
},
|
},
|
||||||
foliage::BinaryOperator::Exponentiate =>
|
foliage::BinaryOperator::Exponentiate =>
|
||||||
Err(crate::Error::new_unsupported_language_feature("exponentiation")),
|
Err(crate::Error::new_unsupported_language_feature("exponentiation")),
|
||||||
@@ -210,41 +197,34 @@ where
|
|||||||
return Err(crate::Error::new_unsupported_language_feature("absolute value")),
|
return Err(crate::Error::new_unsupported_language_feature("absolute value")),
|
||||||
clingo::ast::UnaryOperator::Minus =>
|
clingo::ast::UnaryOperator::Minus =>
|
||||||
{
|
{
|
||||||
let parameter_z_prime = std::rc::Rc::new(foliage::VariableDeclaration::new(
|
let parameter_z_prime = std::rc::Rc::new(
|
||||||
"<anonymous>".to_string()));
|
crate::VariableDeclaration::new_generated(crate::Domain::Integer));
|
||||||
context.assign_variable_declaration_domain(¶meter_z_prime,
|
|
||||||
crate::Domain::Integer);
|
|
||||||
|
|
||||||
let negative_z_prime = foliage::Term::negative(Box::new(
|
let negative_z_prime = crate::Term::negative(Box::new(
|
||||||
foliage::Term::variable(std::rc::Rc::clone(¶meter_z_prime))));
|
crate::Term::variable(std::rc::Rc::clone(¶meter_z_prime))));
|
||||||
let equals = foliage::Formula::equal(
|
let equals = crate::Formula::equal(
|
||||||
Box::new(foliage::Term::variable(variable_declaration)),
|
Box::new(crate::Term::variable(variable_declaration)),
|
||||||
Box::new(negative_z_prime));
|
Box::new(negative_z_prime));
|
||||||
|
|
||||||
let choose_z_prime_in_t_prime = choose_value_in_term(unary_operation.argument(),
|
let choose_z_prime_in_t_prime = choose_value_in_term(unary_operation.argument(),
|
||||||
std::rc::Rc::clone(¶meter_z_prime), context,
|
std::rc::Rc::clone(¶meter_z_prime), context,
|
||||||
variable_declaration_stack)?;
|
variable_declaration_stack)?;
|
||||||
|
|
||||||
let and = foliage::Formula::and(vec![equals, choose_z_prime_in_t_prime]);
|
let and = crate::Formula::and(vec![equals, choose_z_prime_in_t_prime]);
|
||||||
|
|
||||||
let parameters = std::rc::Rc::new(vec![parameter_z_prime]);
|
let parameters = std::rc::Rc::new(vec![parameter_z_prime]);
|
||||||
|
|
||||||
Ok(foliage::Formula::exists(parameters, Box::new(and)))
|
Ok(crate::Formula::exists(parameters, Box::new(and)))
|
||||||
},
|
},
|
||||||
_ => Err(crate::Error::new_not_yet_implemented("todo")),
|
_ => Err(crate::Error::new_not_yet_implemented("todo")),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clingo::ast::TermType::Interval(interval) =>
|
clingo::ast::TermType::Interval(interval) =>
|
||||||
{
|
{
|
||||||
let parameters = (0..3).map(|_|
|
let parameters = (0..3).map(
|
||||||
{
|
|_| std::rc::Rc::new(crate::VariableDeclaration::new_generated(
|
||||||
let variable_declaration = std::rc::Rc::new(
|
crate::Domain::Integer)))
|
||||||
foliage::VariableDeclaration::new("<anonymous>".to_string()));
|
.collect::<crate::VariableDeclarations>();
|
||||||
context.assign_variable_declaration_domain(&variable_declaration,
|
|
||||||
crate::Domain::Integer);
|
|
||||||
variable_declaration
|
|
||||||
})
|
|
||||||
.collect::<foliage::VariableDeclarations>();
|
|
||||||
let parameters = std::rc::Rc::new(parameters);
|
let parameters = std::rc::Rc::new(parameters);
|
||||||
|
|
||||||
let parameter_i = ¶meters[0];
|
let parameter_i = ¶meters[0];
|
||||||
@@ -257,22 +237,22 @@ where
|
|||||||
let choose_j_in_t_2 = choose_value_in_term(interval.right(),
|
let choose_j_in_t_2 = choose_value_in_term(interval.right(),
|
||||||
std::rc::Rc::clone(parameter_j), context, variable_declaration_stack)?;
|
std::rc::Rc::clone(parameter_j), context, variable_declaration_stack)?;
|
||||||
|
|
||||||
let i_less_than_or_equal_to_k = foliage::Formula::less_or_equal(
|
let i_less_than_or_equal_to_k = crate::Formula::less_or_equal(
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_i))),
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_i))),
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_k))));
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_k))));
|
||||||
|
|
||||||
let k_less_than_or_equal_to_j = foliage::Formula::less_or_equal(
|
let k_less_than_or_equal_to_j = crate::Formula::less_or_equal(
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_k))),
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_k))),
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_j))));
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_j))));
|
||||||
|
|
||||||
let z_equals_k = foliage::Formula::equal(
|
let z_equals_k = crate::Formula::equal(
|
||||||
Box::new(foliage::Term::variable(variable_declaration)),
|
Box::new(crate::Term::variable(variable_declaration)),
|
||||||
Box::new(foliage::Term::variable(std::rc::Rc::clone(parameter_k))));
|
Box::new(crate::Term::variable(std::rc::Rc::clone(parameter_k))));
|
||||||
|
|
||||||
let and = foliage::Formula::and(vec![choose_i_in_t_1, choose_j_in_t_2,
|
let and = crate::Formula::and(vec![choose_i_in_t_1, choose_j_in_t_2,
|
||||||
i_less_than_or_equal_to_k, k_less_than_or_equal_to_j, z_equals_k]);
|
i_less_than_or_equal_to_k, k_less_than_or_equal_to_j, z_equals_k]);
|
||||||
|
|
||||||
Ok(foliage::Formula::exists(parameters, Box::new(and)))
|
Ok(crate::Formula::exists(parameters, Box::new(and)))
|
||||||
},
|
},
|
||||||
clingo::ast::TermType::Function(_) =>
|
clingo::ast::TermType::Function(_) =>
|
||||||
Err(crate::Error::new_unsupported_language_feature("symbolic functions")),
|
Err(crate::Error::new_unsupported_language_feature("symbolic functions")),
|
||||||
|
@@ -3,20 +3,21 @@ mod translate_body;
|
|||||||
|
|
||||||
use head_type::*;
|
use head_type::*;
|
||||||
use translate_body::*;
|
use translate_body::*;
|
||||||
use crate::traits::AssignVariableDeclarationDomain as _;
|
|
||||||
|
use foliage::flavor::{PredicateDeclaration as _};
|
||||||
|
|
||||||
struct PredicateDefinitions
|
struct PredicateDefinitions
|
||||||
{
|
{
|
||||||
pub parameters: std::rc::Rc<foliage::VariableDeclarations>,
|
pub parameters: std::rc::Rc<crate::VariableDeclarations>,
|
||||||
pub definitions: Vec<crate::ScopedFormula>,
|
pub definitions: Vec<crate::OpenFormula>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Definitions =
|
type Definitions =
|
||||||
std::collections::BTreeMap::<std::rc::Rc<foliage::PredicateDeclaration>, PredicateDefinitions>;
|
std::collections::BTreeMap::<std::rc::Rc<crate::PredicateDeclaration>, PredicateDefinitions>;
|
||||||
|
|
||||||
pub(crate) struct Translator<'p>
|
pub(crate) struct Translator<'p>
|
||||||
{
|
{
|
||||||
problem: &'p mut crate::Problem,// TODO: refactor
|
problem: &'p mut crate::Problem,
|
||||||
definitions: Definitions,
|
definitions: Definitions,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ impl<'p> Translator<'p>
|
|||||||
|
|
||||||
pub fn translate<P>(&mut self, program_path: P) -> Result<(), crate::Error>
|
pub fn translate<P>(&mut self, program_path: P) -> Result<(), crate::Error>
|
||||||
where
|
where
|
||||||
P: AsRef<std::path::Path>
|
P: AsRef<std::path::Path>,
|
||||||
{
|
{
|
||||||
// Read input program
|
// Read input program
|
||||||
let program = std::fs::read_to_string(program_path.as_ref())
|
let program = std::fs::read_to_string(program_path.as_ref())
|
||||||
@@ -76,20 +77,7 @@ impl<'p> Translator<'p>
|
|||||||
|
|
||||||
log::info!("read input program “{}”", program_path.as_ref().display());
|
log::info!("read input program “{}”", program_path.as_ref().display());
|
||||||
|
|
||||||
// TODO: reimplement
|
let completed_definition = |predicate_declaration, definitions: &mut Definitions|
|
||||||
/*
|
|
||||||
for (predicate_declaration, predicate_definitions) in self.definitions.iter()
|
|
||||||
{
|
|
||||||
for definition in predicate_definitions.definitions.iter()
|
|
||||||
{
|
|
||||||
log::debug!("definition({}/{}): {}.", predicate_declaration.name,
|
|
||||||
predicate_declaration.arity,
|
|
||||||
foliage::format::display_formula(&definition.formula, self.problem));
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
let completed_definition = |predicate_declaration, definitions: &mut Definitions,
|
|
||||||
problem: &crate::Problem|
|
|
||||||
{
|
{
|
||||||
match definitions.remove(predicate_declaration)
|
match definitions.remove(predicate_declaration)
|
||||||
{
|
{
|
||||||
@@ -99,77 +87,73 @@ impl<'p> Translator<'p>
|
|||||||
let or_arguments = predicate_definitions.definitions.into_iter()
|
let or_arguments = predicate_definitions.definitions.into_iter()
|
||||||
.map(|x| crate::existential_closure(x))
|
.map(|x| crate::existential_closure(x))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let or = foliage::Formula::or(or_arguments);
|
let or = crate::Formula::or(or_arguments);
|
||||||
|
|
||||||
let head_arguments = predicate_definitions.parameters.iter()
|
let head_arguments = predicate_definitions.parameters.iter()
|
||||||
.map(|x| foliage::Term::variable(std::rc::Rc::clone(x)))
|
.map(|x| crate::Term::variable(std::rc::Rc::clone(x)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let head_predicate = foliage::Formula::predicate(
|
let head_predicate = crate::Formula::predicate(
|
||||||
std::rc::Rc::clone(predicate_declaration), head_arguments);
|
std::rc::Rc::clone(predicate_declaration), head_arguments);
|
||||||
|
|
||||||
let completed_definition =
|
let completed_definition =
|
||||||
foliage::Formula::if_and_only_if(vec![head_predicate, or]);
|
crate::Formula::if_and_only_if(vec![head_predicate, or]);
|
||||||
|
|
||||||
let scoped_formula = crate::ScopedFormula
|
let open_formula = crate::OpenFormula
|
||||||
{
|
{
|
||||||
free_variable_declarations: predicate_definitions.parameters,
|
free_variable_declarations: predicate_definitions.parameters,
|
||||||
formula: completed_definition,
|
formula: completed_definition,
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::universal_closure(scoped_formula)
|
crate::universal_closure(open_formula)
|
||||||
},
|
},
|
||||||
// This predicate has no definitions, so universally falsify it
|
// This predicate has no definitions, so universally falsify it
|
||||||
None =>
|
None =>
|
||||||
{
|
{
|
||||||
let parameters = std::rc::Rc::new((0..predicate_declaration.arity)
|
let parameters = std::rc::Rc::new((0..predicate_declaration.arity()).map(
|
||||||
.map(|_|
|
|_| std::rc::Rc::new(crate::VariableDeclaration::new_generated(
|
||||||
{
|
crate::Domain::Program)))
|
||||||
let variable_declaration = std::rc::Rc::new(
|
|
||||||
foliage::VariableDeclaration::new("<anonymous>".to_string()));
|
|
||||||
problem.assign_variable_declaration_domain(&variable_declaration,
|
|
||||||
crate::Domain::Program);
|
|
||||||
variable_declaration
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>());
|
.collect::<Vec<_>>());
|
||||||
|
|
||||||
let head_arguments = parameters.iter()
|
let head_arguments = parameters.iter()
|
||||||
.map(|x| foliage::Term::variable(std::rc::Rc::clone(x)))
|
.map(|x| crate::Term::variable(std::rc::Rc::clone(x)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let head_predicate = foliage::Formula::predicate(
|
let head_predicate = crate::Formula::predicate(
|
||||||
std::rc::Rc::clone(predicate_declaration), head_arguments);
|
std::rc::Rc::clone(predicate_declaration), head_arguments);
|
||||||
|
|
||||||
let not = foliage::Formula::not(Box::new(head_predicate));
|
let not = crate::Formula::not(Box::new(head_predicate));
|
||||||
|
|
||||||
let scoped_formula = crate::ScopedFormula
|
let open_formula = crate::OpenFormula
|
||||||
{
|
{
|
||||||
free_variable_declarations: parameters,
|
free_variable_declarations: parameters,
|
||||||
formula: not,
|
formula: not,
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::universal_closure(scoped_formula)
|
crate::universal_closure(open_formula)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for predicate_declaration in self.problem.predicate_declarations.borrow().iter()
|
for predicate_declaration in self.problem.predicate_declarations.borrow_mut().iter()
|
||||||
{
|
{
|
||||||
// Don’t perform completion for input predicates
|
// Don’t perform completion for input predicates and built-in predicates
|
||||||
if self.problem.input_predicate_declarations.borrow().contains(predicate_declaration)
|
if *predicate_declaration.is_input.borrow() || predicate_declaration.is_built_in()
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let completed_definition =
|
let statement_kind = crate::problem::StatementKind::CompletedDefinition(
|
||||||
completed_definition(predicate_declaration, &mut self.definitions, self.problem);
|
std::rc::Rc::clone(&predicate_declaration));
|
||||||
|
|
||||||
let statement = crate::problem::Statement::new(
|
let completed_definition = completed_definition(predicate_declaration,
|
||||||
crate::problem::StatementKind::Program, completed_definition)
|
&mut self.definitions);
|
||||||
.with_name(format!("completed_definition_{}_{}", predicate_declaration.name,
|
|
||||||
predicate_declaration.arity))
|
let statement_name =
|
||||||
.with_description(format!("completed definition of {}/{}",
|
format!("completed_definition_{}", predicate_declaration.tptp_statement_name());
|
||||||
predicate_declaration.name, predicate_declaration.arity));
|
|
||||||
|
let statement = crate::problem::Statement::new(statement_kind, completed_definition)
|
||||||
|
.with_name(statement_name);
|
||||||
|
|
||||||
self.problem.add_statement(crate::problem::SectionKind::CompletedDefinitions,
|
self.problem.add_statement(crate::problem::SectionKind::CompletedDefinitions,
|
||||||
statement);
|
statement);
|
||||||
@@ -190,15 +174,10 @@ impl<'p> Translator<'p>
|
|||||||
{
|
{
|
||||||
if !self.definitions.contains_key(&head_atom.predicate_declaration)
|
if !self.definitions.contains_key(&head_atom.predicate_declaration)
|
||||||
{
|
{
|
||||||
let parameters = std::rc::Rc::new((0..head_atom.predicate_declaration.arity)
|
let parameters = std::rc::Rc::new((0..head_atom.predicate_declaration.arity())
|
||||||
.map(|_|
|
.map(
|
||||||
{
|
|_| std::rc::Rc::new(crate::VariableDeclaration::new_generated(
|
||||||
let variable_declaration = std::rc::Rc::new(
|
crate::Domain::Program)))
|
||||||
foliage::VariableDeclaration::new("<anonymous>".to_string()));
|
|
||||||
self.problem.assign_variable_declaration_domain(&variable_declaration,
|
|
||||||
crate::Domain::Program);
|
|
||||||
variable_declaration
|
|
||||||
})
|
|
||||||
.collect());
|
.collect());
|
||||||
|
|
||||||
self.definitions.insert(
|
self.definitions.insert(
|
||||||
@@ -217,12 +196,24 @@ impl<'p> Translator<'p>
|
|||||||
let parameters = std::rc::Rc::clone(&predicate_definitions.parameters);
|
let parameters = std::rc::Rc::clone(&predicate_definitions.parameters);
|
||||||
let free_variable_declarations = std::cell::RefCell::new(vec![]);
|
let free_variable_declarations = std::cell::RefCell::new(vec![]);
|
||||||
let free_layer =
|
let free_layer =
|
||||||
foliage::VariableDeclarationStackLayer::Free(free_variable_declarations);
|
crate::VariableDeclarationStackLayer::Free(free_variable_declarations);
|
||||||
let parameters_layer =
|
let parameters_layer =
|
||||||
foliage::VariableDeclarationStackLayer::bound(&free_layer, parameters);
|
crate::VariableDeclarationStackLayer::bound(&free_layer, parameters);
|
||||||
|
|
||||||
|
let mut predicate_dependencies =
|
||||||
|
head_atom.predicate_declaration.dependencies.borrow_mut();
|
||||||
|
|
||||||
|
if predicate_dependencies.is_none()
|
||||||
|
{
|
||||||
|
*predicate_dependencies = Some(crate::PredicateDependencies::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
// The conditional assignment above ensures unwrapping to be safe
|
||||||
|
let mut dependencies = predicate_dependencies.as_mut().unwrap();
|
||||||
|
|
||||||
let mut definition_arguments =
|
let mut definition_arguments =
|
||||||
translate_body(rule.body(), self.problem, ¶meters_layer)?;
|
translate_body(rule.body(), self.problem, ¶meters_layer,
|
||||||
|
&mut Some(&mut dependencies))?;
|
||||||
|
|
||||||
// TODO: refactor
|
// TODO: refactor
|
||||||
assert_eq!(predicate_definitions.parameters.len(), head_atom.arguments.len());
|
assert_eq!(predicate_definitions.parameters.len(), head_atom.arguments.len());
|
||||||
@@ -230,10 +221,10 @@ impl<'p> Translator<'p>
|
|||||||
if let HeadType::ChoiceWithSingleAtom(_) = head_type
|
if let HeadType::ChoiceWithSingleAtom(_) = head_type
|
||||||
{
|
{
|
||||||
let head_arguments = predicate_definitions.parameters.iter()
|
let head_arguments = predicate_definitions.parameters.iter()
|
||||||
.map(|x| foliage::Term::variable(std::rc::Rc::clone(x)))
|
.map(|x| crate::Term::variable(std::rc::Rc::clone(x)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let head_predicate = foliage::Formula::predicate(
|
let head_predicate = crate::Formula::predicate(
|
||||||
std::rc::Rc::clone(&head_atom.predicate_declaration), head_arguments);
|
std::rc::Rc::clone(&head_atom.predicate_declaration), head_arguments);
|
||||||
|
|
||||||
definition_arguments.push(head_predicate);
|
definition_arguments.push(head_predicate);
|
||||||
@@ -255,7 +246,7 @@ impl<'p> Translator<'p>
|
|||||||
// TODO: refactor
|
// TODO: refactor
|
||||||
let free_variable_declarations = match free_layer
|
let free_variable_declarations = match free_layer
|
||||||
{
|
{
|
||||||
foliage::VariableDeclarationStackLayer::Free(free_variable_declarations)
|
crate::VariableDeclarationStackLayer::Free(free_variable_declarations)
|
||||||
=> free_variable_declarations.into_inner(),
|
=> free_variable_declarations.into_inner(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
@@ -263,67 +254,53 @@ impl<'p> Translator<'p>
|
|||||||
let definition = match definition_arguments.len()
|
let definition = match definition_arguments.len()
|
||||||
{
|
{
|
||||||
1 => definition_arguments.pop().unwrap(),
|
1 => definition_arguments.pop().unwrap(),
|
||||||
0 => foliage::Formula::true_(),
|
0 => crate::Formula::true_(),
|
||||||
_ => foliage::Formula::and(definition_arguments),
|
_ => crate::Formula::and(definition_arguments),
|
||||||
};
|
};
|
||||||
|
|
||||||
let definition = crate::ScopedFormula
|
let definition = crate::OpenFormula
|
||||||
{
|
{
|
||||||
free_variable_declarations: std::rc::Rc::new(free_variable_declarations),
|
free_variable_declarations: std::rc::Rc::new(free_variable_declarations),
|
||||||
formula: definition,
|
formula: definition,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: refactor
|
|
||||||
// TODO: reimplement
|
|
||||||
/*
|
|
||||||
log::debug!("translated rule with single atom in head: {}",
|
|
||||||
foliage::format::display_formula(&definition.formula, self.problem));
|
|
||||||
*/
|
|
||||||
|
|
||||||
predicate_definitions.definitions.push(definition);
|
predicate_definitions.definitions.push(definition);
|
||||||
},
|
},
|
||||||
HeadType::IntegrityConstraint =>
|
HeadType::IntegrityConstraint =>
|
||||||
{
|
{
|
||||||
let free_variable_declarations = std::cell::RefCell::new(vec![]);
|
let free_variable_declarations = std::cell::RefCell::new(vec![]);
|
||||||
let free_layer =
|
let free_layer =
|
||||||
foliage::VariableDeclarationStackLayer::Free(free_variable_declarations);
|
crate::VariableDeclarationStackLayer::Free(free_variable_declarations);
|
||||||
|
|
||||||
let mut arguments = translate_body(rule.body(), self.problem, &free_layer)?;
|
let mut arguments = translate_body(rule.body(), self.problem, &free_layer,
|
||||||
|
&mut None)?;
|
||||||
|
|
||||||
// TODO: refactor
|
// TODO: refactor
|
||||||
let free_variable_declarations = match free_layer
|
let free_variable_declarations = match free_layer
|
||||||
{
|
{
|
||||||
foliage::VariableDeclarationStackLayer::Free(free_variable_declarations)
|
crate::VariableDeclarationStackLayer::Free(free_variable_declarations)
|
||||||
=> free_variable_declarations.into_inner(),
|
=> free_variable_declarations.into_inner(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let formula = match arguments.len()
|
let formula = match arguments.len()
|
||||||
{
|
{
|
||||||
1 => foliage::Formula::not(Box::new(arguments.pop().unwrap())),
|
1 => crate::Formula::not(Box::new(arguments.pop().unwrap())),
|
||||||
0 => foliage::Formula::false_(),
|
0 => crate::Formula::false_(),
|
||||||
_ => foliage::Formula::not(Box::new(foliage::Formula::and(arguments))),
|
_ => crate::Formula::not(Box::new(crate::Formula::and(arguments))),
|
||||||
};
|
};
|
||||||
|
|
||||||
let scoped_formula = crate::ScopedFormula
|
let open_formula = crate::OpenFormula
|
||||||
{
|
{
|
||||||
free_variable_declarations: std::rc::Rc::new(free_variable_declarations),
|
free_variable_declarations: std::rc::Rc::new(free_variable_declarations),
|
||||||
formula,
|
formula,
|
||||||
};
|
};
|
||||||
|
|
||||||
let integrity_constraint = crate::universal_closure(scoped_formula);
|
let integrity_constraint = crate::universal_closure(open_formula);
|
||||||
|
|
||||||
// TODO: refactor
|
|
||||||
// TODO: reimplement
|
|
||||||
/*
|
|
||||||
log::debug!("translated integrity constraint: {}",
|
|
||||||
foliage::format::display_formula(&integrity_constraint, self.problem));
|
|
||||||
*/
|
|
||||||
|
|
||||||
let statement = crate::problem::Statement::new(
|
let statement = crate::problem::Statement::new(
|
||||||
crate::problem::StatementKind::Program, integrity_constraint)
|
crate::problem::StatementKind::IntegrityConstraint, integrity_constraint)
|
||||||
.with_name("integrity_constraint".to_string())
|
.with_name("integrity_constraint".to_string());
|
||||||
.with_description("integrity constraint".to_string());
|
|
||||||
|
|
||||||
self.problem.add_statement(crate::problem::SectionKind::IntegrityConstraints,
|
self.problem.add_statement(crate::problem::SectionKind::IntegrityConstraints,
|
||||||
statement);
|
statement);
|
||||||
|
@@ -1,195 +0,0 @@
|
|||||||
/*pub(crate) struct Definitions
|
|
||||||
{
|
|
||||||
pub head_atom_parameters: std::rc::Rc<foliage::VariableDeclarations>,
|
|
||||||
pub definitions: Vec<crate::ScopedFormula>,
|
|
||||||
}
|
|
||||||
|
|
||||||
type VariableDeclarationDomains
|
|
||||||
= std::collections::BTreeMap<std::rc::Rc<foliage::VariableDeclaration>, crate::Domain>;
|
|
||||||
|
|
||||||
type VariableDeclarationIDs
|
|
||||||
= std::collections::BTreeMap::<std::rc::Rc<foliage::VariableDeclaration>, usize>;
|
|
||||||
|
|
||||||
pub(crate) struct Context
|
|
||||||
{
|
|
||||||
pub definitions: std::cell::RefCell<std::collections::BTreeMap::<
|
|
||||||
std::rc::Rc<foliage::PredicateDeclaration>, Definitions>>,
|
|
||||||
pub integrity_constraints: std::cell::RefCell<foliage::Formulas>,
|
|
||||||
|
|
||||||
pub input_constant_declaration_domains: std::cell::RefCell<
|
|
||||||
crate::InputConstantDeclarationDomains>,
|
|
||||||
pub input_predicate_declarations: std::cell::RefCell<foliage::PredicateDeclarations>,
|
|
||||||
|
|
||||||
pub function_declarations: std::cell::RefCell<foliage::FunctionDeclarations>,
|
|
||||||
pub predicate_declarations: std::cell::RefCell<foliage::PredicateDeclarations>,
|
|
||||||
pub variable_declaration_domains: std::cell::RefCell<VariableDeclarationDomains>,
|
|
||||||
pub program_variable_declaration_ids: std::cell::RefCell<VariableDeclarationIDs>,
|
|
||||||
pub integer_variable_declaration_ids: std::cell::RefCell<VariableDeclarationIDs>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Context
|
|
||||||
{
|
|
||||||
pub(crate) fn new() -> Self
|
|
||||||
{
|
|
||||||
Self
|
|
||||||
{
|
|
||||||
definitions: std::cell::RefCell::new(std::collections::BTreeMap::<_, _>::new()),
|
|
||||||
integrity_constraints: std::cell::RefCell::new(vec![]),
|
|
||||||
|
|
||||||
input_constant_declaration_domains:
|
|
||||||
std::cell::RefCell::new(crate::InputConstantDeclarationDomains::new()),
|
|
||||||
input_predicate_declarations:
|
|
||||||
std::cell::RefCell::new(foliage::PredicateDeclarations::new()),
|
|
||||||
|
|
||||||
function_declarations: std::cell::RefCell::new(foliage::FunctionDeclarations::new()),
|
|
||||||
predicate_declarations: std::cell::RefCell::new(foliage::PredicateDeclarations::new()),
|
|
||||||
variable_declaration_domains:
|
|
||||||
std::cell::RefCell::new(VariableDeclarationDomains::new()),
|
|
||||||
program_variable_declaration_ids:
|
|
||||||
std::cell::RefCell::new(VariableDeclarationIDs::new()),
|
|
||||||
integer_variable_declaration_ids:
|
|
||||||
std::cell::RefCell::new(VariableDeclarationIDs::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::traits::InputConstantDeclarationDomain for Context
|
|
||||||
{
|
|
||||||
fn input_constant_declaration_domain(&self,
|
|
||||||
declaration: &std::rc::Rc<foliage::FunctionDeclaration>) -> crate::Domain
|
|
||||||
{
|
|
||||||
let input_constant_declaration_domains = self.input_constant_declaration_domains.borrow();
|
|
||||||
|
|
||||||
// Assume the program domain if not specified otherwise
|
|
||||||
input_constant_declaration_domains.get(declaration).map(|x| *x)
|
|
||||||
.unwrap_or(crate::Domain::Program)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl foliage::FindOrCreateFunctionDeclaration for Context
|
|
||||||
{
|
|
||||||
fn find_or_create_function_declaration(&self, name: &str, arity: usize)
|
|
||||||
-> std::rc::Rc<foliage::FunctionDeclaration>
|
|
||||||
{
|
|
||||||
let mut function_declarations = self.function_declarations.borrow_mut();
|
|
||||||
|
|
||||||
match function_declarations.iter()
|
|
||||||
.find(|x| x.name == name && x.arity == arity)
|
|
||||||
{
|
|
||||||
Some(value) => std::rc::Rc::clone(value),
|
|
||||||
None =>
|
|
||||||
{
|
|
||||||
let declaration = std::rc::Rc::new(foliage::FunctionDeclaration::new(
|
|
||||||
name.to_string(), arity));
|
|
||||||
|
|
||||||
function_declarations.insert(std::rc::Rc::clone(&declaration));
|
|
||||||
|
|
||||||
log::debug!("new function declaration: {}/{}", name, arity);
|
|
||||||
|
|
||||||
declaration
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl foliage::FindOrCreatePredicateDeclaration for Context
|
|
||||||
{
|
|
||||||
fn find_or_create_predicate_declaration(&self, name: &str, arity: usize)
|
|
||||||
-> std::rc::Rc<foliage::PredicateDeclaration>
|
|
||||||
{
|
|
||||||
let mut predicate_declarations = self.predicate_declarations.borrow_mut();
|
|
||||||
|
|
||||||
match predicate_declarations.iter()
|
|
||||||
.find(|x| x.name == name && x.arity == arity)
|
|
||||||
{
|
|
||||||
Some(value) => std::rc::Rc::clone(value),
|
|
||||||
None =>
|
|
||||||
{
|
|
||||||
let declaration = std::rc::Rc::new(foliage::PredicateDeclaration::new(
|
|
||||||
name.to_string(), arity));
|
|
||||||
|
|
||||||
predicate_declarations.insert(std::rc::Rc::clone(&declaration));
|
|
||||||
|
|
||||||
log::debug!("new predicate declaration: {}/{}", name, arity);
|
|
||||||
|
|
||||||
declaration
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::traits::AssignVariableDeclarationDomain for Context
|
|
||||||
{
|
|
||||||
fn assign_variable_declaration_domain(&self,
|
|
||||||
variable_declaration: &std::rc::Rc<foliage::VariableDeclaration>, domain: crate::Domain)
|
|
||||||
{
|
|
||||||
let mut variable_declaration_domains = self.variable_declaration_domains.borrow_mut();
|
|
||||||
|
|
||||||
match variable_declaration_domains.get(variable_declaration)
|
|
||||||
{
|
|
||||||
Some(current_domain) => assert_eq!(*current_domain, domain,
|
|
||||||
"inconsistent variable declaration domain"),
|
|
||||||
None =>
|
|
||||||
{
|
|
||||||
variable_declaration_domains
|
|
||||||
.insert(std::rc::Rc::clone(variable_declaration).into(), domain);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::traits::VariableDeclarationDomain for Context
|
|
||||||
{
|
|
||||||
fn variable_declaration_domain(&self,
|
|
||||||
variable_declaration: &std::rc::Rc<foliage::VariableDeclaration>)
|
|
||||||
-> Option<crate::Domain>
|
|
||||||
{
|
|
||||||
let variable_declaration_domains = self.variable_declaration_domains.borrow();
|
|
||||||
|
|
||||||
variable_declaration_domains.get(variable_declaration)
|
|
||||||
.map(|x| *x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::traits::VariableDeclarationID for Context
|
|
||||||
{
|
|
||||||
fn variable_declaration_id(&self,
|
|
||||||
variable_declaration: &std::rc::Rc<foliage::VariableDeclaration>)
|
|
||||||
-> usize
|
|
||||||
{
|
|
||||||
use crate::traits::VariableDeclarationDomain;
|
|
||||||
|
|
||||||
let mut variable_declaration_ids = match self.variable_declaration_domain(
|
|
||||||
variable_declaration)
|
|
||||||
{
|
|
||||||
Some(crate::Domain::Program) => self.program_variable_declaration_ids.borrow_mut(),
|
|
||||||
Some(crate::Domain::Integer) => self.integer_variable_declaration_ids.borrow_mut(),
|
|
||||||
None => panic!("all variables should be declared at this point"),
|
|
||||||
};
|
|
||||||
|
|
||||||
match variable_declaration_ids.get(variable_declaration)
|
|
||||||
{
|
|
||||||
Some(id) =>
|
|
||||||
{
|
|
||||||
*id
|
|
||||||
}
|
|
||||||
None =>
|
|
||||||
{
|
|
||||||
let id = variable_declaration_ids.len();
|
|
||||||
variable_declaration_ids.insert(std::rc::Rc::clone(variable_declaration).into(), id);
|
|
||||||
id
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl foliage::format::Format for Context
|
|
||||||
{
|
|
||||||
fn display_variable_declaration(&self, formatter: &mut std::fmt::Formatter,
|
|
||||||
variable_declaration: &std::rc::Rc<foliage::VariableDeclaration>)
|
|
||||||
-> std::fmt::Result
|
|
||||||
{
|
|
||||||
crate::output::human_readable::display_variable_declaration(self, formatter,
|
|
||||||
variable_declaration)
|
|
||||||
}
|
|
||||||
}*/
|
|
@@ -1,6 +1,6 @@
|
|||||||
pub(crate) struct HeadAtom<'a>
|
pub(crate) struct HeadAtom<'a>
|
||||||
{
|
{
|
||||||
pub predicate_declaration: std::rc::Rc<foliage::PredicateDeclaration>,
|
pub predicate_declaration: std::rc::Rc<crate::PredicateDeclaration>,
|
||||||
pub arguments: &'a [clingo::ast::Term<'a>],
|
pub arguments: &'a [clingo::ast::Term<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ pub(crate) enum HeadType<'a>
|
|||||||
pub(crate) fn determine_head_type<'a, C>(head_literal: &'a clingo::ast::HeadLiteral, context: &C)
|
pub(crate) fn determine_head_type<'a, C>(head_literal: &'a clingo::ast::HeadLiteral, context: &C)
|
||||||
-> Result<HeadType<'a>, crate::Error>
|
-> Result<HeadType<'a>, crate::Error>
|
||||||
where
|
where
|
||||||
C: foliage::FindOrCreatePredicateDeclaration
|
C: foliage::FindOrCreatePredicateDeclaration<crate::FoliageFlavor>
|
||||||
{
|
{
|
||||||
let create_head_atom = |function: &'a clingo::ast::Function| -> Result<_, crate::Error>
|
let create_head_atom = |function: &'a clingo::ast::Function| -> Result<_, crate::Error>
|
||||||
{
|
{
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
// TODO: rename context
|
// TODO: rename context
|
||||||
pub(crate) fn translate_body_term<C>(body_term: &clingo::ast::Term, sign: clingo::ast::Sign,
|
pub(crate) fn translate_body_term<C>(body_term: &clingo::ast::Term, sign: clingo::ast::Sign,
|
||||||
context: &C, variable_declaration_stack: &foliage::VariableDeclarationStackLayer)
|
context: &C, variable_declaration_stack: &crate::VariableDeclarationStackLayer,
|
||||||
-> Result<foliage::Formula, crate::Error>
|
head_predicate_dependencies: &mut Option<&mut crate::PredicateDependencies>)
|
||||||
|
-> Result<crate::Formula, crate::Error>
|
||||||
where
|
where
|
||||||
C: foliage::FindOrCreateFunctionDeclaration
|
C: foliage::FindOrCreateFunctionDeclaration<crate::FoliageFlavor>
|
||||||
+ foliage::FindOrCreatePredicateDeclaration
|
+ foliage::FindOrCreatePredicateDeclaration<crate::FoliageFlavor>,
|
||||||
+ crate::traits::AssignVariableDeclarationDomain
|
|
||||||
{
|
{
|
||||||
let function = match body_term.term_type()
|
let function = match body_term.term_type()
|
||||||
{
|
{
|
||||||
@@ -18,22 +18,42 @@ where
|
|||||||
let predicate_declaration = context.find_or_create_predicate_declaration(function_name,
|
let predicate_declaration = context.find_or_create_predicate_declaration(function_name,
|
||||||
function.arguments().len());
|
function.arguments().len());
|
||||||
|
|
||||||
let parameters = function.arguments().iter().map(|_|
|
let parameters = function.arguments().iter().map(
|
||||||
{
|
|_| std::rc::Rc::new(crate::VariableDeclaration::new_generated(crate::Domain::Program)))
|
||||||
let variable_declaration = std::rc::Rc::new(
|
.collect::<crate::VariableDeclarations>();
|
||||||
foliage::VariableDeclaration::new("<anonymous>".to_string()));
|
|
||||||
context.assign_variable_declaration_domain(&variable_declaration,
|
|
||||||
crate::Domain::Program);
|
|
||||||
variable_declaration
|
|
||||||
})
|
|
||||||
.collect::<foliage::VariableDeclarations>();
|
|
||||||
let parameters = std::rc::Rc::new(parameters);
|
let parameters = std::rc::Rc::new(parameters);
|
||||||
|
|
||||||
let predicate_arguments = parameters.iter().map(
|
let predicate_arguments = parameters.iter().map(
|
||||||
|parameter| foliage::Term::variable(std::rc::Rc::clone(parameter)))
|
|parameter| crate::Term::variable(std::rc::Rc::clone(parameter)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let predicate = foliage::Formula::predicate(predicate_declaration, predicate_arguments);
|
if let Some(head_predicate_dependencies) = head_predicate_dependencies
|
||||||
|
{
|
||||||
|
match head_predicate_dependencies.get_mut(&predicate_declaration)
|
||||||
|
{
|
||||||
|
None =>
|
||||||
|
{
|
||||||
|
let predicate_dependency_sign = match sign
|
||||||
|
{
|
||||||
|
clingo::ast::Sign::None
|
||||||
|
| clingo::ast::Sign::DoubleNegation => crate::PredicateDependencySign::OnlyPositive,
|
||||||
|
clingo::ast::Sign::Negation => crate::PredicateDependencySign::OnlyNegative,
|
||||||
|
};
|
||||||
|
|
||||||
|
head_predicate_dependencies.insert(
|
||||||
|
std::rc::Rc::clone(&predicate_declaration), predicate_dependency_sign);
|
||||||
|
},
|
||||||
|
Some(predicate_dependency_sign) =>
|
||||||
|
*predicate_dependency_sign = match sign
|
||||||
|
{
|
||||||
|
clingo::ast::Sign::None
|
||||||
|
| clingo::ast::Sign::DoubleNegation => predicate_dependency_sign.and_positive(),
|
||||||
|
clingo::ast::Sign::Negation => predicate_dependency_sign.and_negative(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let predicate = crate::Formula::predicate(predicate_declaration, predicate_arguments);
|
||||||
|
|
||||||
let predicate_literal = match sign
|
let predicate_literal = match sign
|
||||||
{
|
{
|
||||||
@@ -41,7 +61,7 @@ where
|
|||||||
| clingo::ast::Sign::DoubleNegation
|
| clingo::ast::Sign::DoubleNegation
|
||||||
=> predicate,
|
=> predicate,
|
||||||
clingo::ast::Sign::Negation
|
clingo::ast::Sign::Negation
|
||||||
=> foliage::Formula::not(Box::new(predicate)),
|
=> crate::Formula::not(Box::new(predicate)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if function.arguments().is_empty()
|
if function.arguments().is_empty()
|
||||||
@@ -60,18 +80,18 @@ where
|
|||||||
|
|
||||||
arguments.push(predicate_literal);
|
arguments.push(predicate_literal);
|
||||||
|
|
||||||
let and = foliage::Formula::and(arguments);
|
let and = crate::Formula::and(arguments);
|
||||||
|
|
||||||
Ok(foliage::Formula::exists(parameters, Box::new(and)))
|
Ok(crate::Formula::exists(parameters, Box::new(and)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn translate_body_literal<C>(body_literal: &clingo::ast::BodyLiteral,
|
pub(crate) fn translate_body_literal<C>(body_literal: &clingo::ast::BodyLiteral,
|
||||||
context: &C, variable_declaration_stack: &foliage::VariableDeclarationStackLayer)
|
context: &C, variable_declaration_stack: &crate::VariableDeclarationStackLayer,
|
||||||
-> Result<foliage::Formula, crate::Error>
|
head_predicate_dependencies: &mut Option<&mut crate::PredicateDependencies>)
|
||||||
|
-> Result<crate::Formula, crate::Error>
|
||||||
where
|
where
|
||||||
C: foliage::FindOrCreateFunctionDeclaration
|
C: foliage::FindOrCreateFunctionDeclaration<crate::FoliageFlavor>
|
||||||
+ foliage::FindOrCreatePredicateDeclaration
|
+ foliage::FindOrCreatePredicateDeclaration<crate::FoliageFlavor>,
|
||||||
+ crate::traits::AssignVariableDeclarationDomain
|
|
||||||
{
|
{
|
||||||
match body_literal.sign()
|
match body_literal.sign()
|
||||||
{
|
{
|
||||||
@@ -97,21 +117,16 @@ where
|
|||||||
_ => return Err(crate::Error::new_logic("unexpected negated Boolean value")),
|
_ => return Err(crate::Error::new_logic("unexpected negated Boolean value")),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(foliage::Formula::Boolean(value))
|
Ok(crate::Formula::Boolean(value))
|
||||||
},
|
},
|
||||||
clingo::ast::LiteralType::Symbolic(term) => translate_body_term(term, literal.sign(),
|
clingo::ast::LiteralType::Symbolic(term) => translate_body_term(term, literal.sign(),
|
||||||
context, variable_declaration_stack),
|
context, variable_declaration_stack, head_predicate_dependencies),
|
||||||
clingo::ast::LiteralType::Comparison(comparison) =>
|
clingo::ast::LiteralType::Comparison(comparison) =>
|
||||||
{
|
{
|
||||||
let parameters = (0..2).map(|_|
|
let parameters = (0..2).map(
|
||||||
{
|
|_| std::rc::Rc::new(crate::VariableDeclaration::new_generated(
|
||||||
let variable_declaration = std::rc::Rc::new(
|
crate::Domain::Program)))
|
||||||
foliage::VariableDeclaration::new("<anonymous>".to_string()));
|
.collect::<crate::VariableDeclarations>();
|
||||||
context.assign_variable_declaration_domain(&variable_declaration,
|
|
||||||
crate::Domain::Program);
|
|
||||||
variable_declaration
|
|
||||||
})
|
|
||||||
.collect::<foliage::VariableDeclarations>();
|
|
||||||
let parameters = std::rc::Rc::new(parameters);
|
let parameters = std::rc::Rc::new(parameters);
|
||||||
|
|
||||||
let mut parameters_iterator = parameters.iter();
|
let mut parameters_iterator = parameters.iter();
|
||||||
@@ -123,19 +138,19 @@ where
|
|||||||
let choose_z2_in_t2 = crate::translate::common::choose_value_in_term(comparison.right(),
|
let choose_z2_in_t2 = crate::translate::common::choose_value_in_term(comparison.right(),
|
||||||
std::rc::Rc::clone(parameter_z2), context, variable_declaration_stack)?;
|
std::rc::Rc::clone(parameter_z2), context, variable_declaration_stack)?;
|
||||||
|
|
||||||
let variable_1 = foliage::Term::variable(std::rc::Rc::clone(parameter_z1));
|
let variable_1 = crate::Term::variable(std::rc::Rc::clone(parameter_z1));
|
||||||
let variable_2 = foliage::Term::variable(std::rc::Rc::clone(parameter_z2));
|
let variable_2 = crate::Term::variable(std::rc::Rc::clone(parameter_z2));
|
||||||
|
|
||||||
let operator = crate::translate::common::translate_comparison_operator(
|
let operator = crate::translate::common::translate_comparison_operator(
|
||||||
comparison.comparison_type());
|
comparison.comparison_type());
|
||||||
|
|
||||||
let compare_z1_and_z2 = foliage::Formula::compare(operator, Box::new(variable_1),
|
let compare_z1_and_z2 = crate::Formula::compare(operator, Box::new(variable_1),
|
||||||
Box::new(variable_2));
|
Box::new(variable_2));
|
||||||
|
|
||||||
let and =
|
let and =
|
||||||
foliage::Formula::and(vec![choose_z1_in_t1, choose_z2_in_t2, compare_z1_and_z2]);
|
crate::Formula::and(vec![choose_z1_in_t1, choose_z2_in_t2, compare_z1_and_z2]);
|
||||||
|
|
||||||
Ok(foliage::Formula::exists(parameters, Box::new(and)))
|
Ok(crate::Formula::exists(parameters, Box::new(and)))
|
||||||
},
|
},
|
||||||
_ => Err(crate::Error::new_unsupported_language_feature(
|
_ => Err(crate::Error::new_unsupported_language_feature(
|
||||||
"body literals other than Booleans, terms, or comparisons")),
|
"body literals other than Booleans, terms, or comparisons")),
|
||||||
@@ -143,15 +158,16 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn translate_body<C>(body_literals: &[clingo::ast::BodyLiteral], context: &C,
|
pub(crate) fn translate_body<C>(body_literals: &[clingo::ast::BodyLiteral], context: &C,
|
||||||
variable_declaration_stack: &foliage::VariableDeclarationStackLayer)
|
variable_declaration_stack: &crate::VariableDeclarationStackLayer,
|
||||||
-> Result<foliage::Formulas, crate::Error>
|
// TODO: refactor
|
||||||
|
mut head_predicate_dependencies: &mut Option<&mut crate::PredicateDependencies>)
|
||||||
|
-> Result<crate::Formulas, crate::Error>
|
||||||
where
|
where
|
||||||
C: foliage::FindOrCreateFunctionDeclaration
|
C: foliage::FindOrCreateFunctionDeclaration<crate::FoliageFlavor>
|
||||||
+ foliage::FindOrCreatePredicateDeclaration
|
+ foliage::FindOrCreatePredicateDeclaration<crate::FoliageFlavor>,
|
||||||
+ crate::traits::AssignVariableDeclarationDomain
|
|
||||||
{
|
{
|
||||||
body_literals.iter()
|
body_literals.iter()
|
||||||
.map(|body_literal| translate_body_literal(body_literal, context,
|
.map(|body_literal| translate_body_literal(body_literal, context,
|
||||||
variable_declaration_stack))
|
variable_declaration_stack, &mut head_predicate_dependencies))
|
||||||
.collect::<Result<foliage::Formulas, crate::Error>>()
|
.collect::<Result<crate::Formulas, crate::Error>>()
|
||||||
}
|
}
|
||||||
|
164
src/utils.rs
164
src/utils.rs
@@ -1,6 +1,18 @@
|
|||||||
mod arithmetic_terms;
|
mod arithmetic_terms;
|
||||||
|
mod autoname_variables;
|
||||||
|
mod closures;
|
||||||
|
mod copy_formula;
|
||||||
|
mod fold_predicates;
|
||||||
|
mod formula_contains_predicate;
|
||||||
|
mod variables_in_terms;
|
||||||
|
|
||||||
|
pub(crate) use autoname_variables::*;
|
||||||
pub(crate) use arithmetic_terms::*;
|
pub(crate) use arithmetic_terms::*;
|
||||||
|
pub(crate) use closures::*;
|
||||||
|
pub(crate) use copy_formula::*;
|
||||||
|
pub(crate) use fold_predicates::*;
|
||||||
|
pub(crate) use formula_contains_predicate::*;
|
||||||
|
pub(crate) use variables_in_terms::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
pub(crate) enum OperatorNotation
|
pub(crate) enum OperatorNotation
|
||||||
@@ -35,155 +47,3 @@ impl std::fmt::Display for Domain
|
|||||||
write!(formatter, "{:?}", self)
|
write!(formatter, "{:?}", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
|
||||||
pub enum ProofDirection
|
|
||||||
{
|
|
||||||
Forward,
|
|
||||||
Backward,
|
|
||||||
Both,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for ProofDirection
|
|
||||||
{
|
|
||||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
|
||||||
{
|
|
||||||
match self
|
|
||||||
{
|
|
||||||
ProofDirection::Forward => write!(formatter, "forward"),
|
|
||||||
ProofDirection::Backward => write!(formatter, "backward"),
|
|
||||||
ProofDirection::Both => write!(formatter, "both"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for ProofDirection
|
|
||||||
{
|
|
||||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
|
||||||
{
|
|
||||||
write!(formatter, "{:?}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InvalidProofDirectionError;
|
|
||||||
|
|
||||||
impl std::fmt::Debug for InvalidProofDirectionError
|
|
||||||
{
|
|
||||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
|
||||||
{
|
|
||||||
write!(formatter, "invalid proof direction")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for InvalidProofDirectionError
|
|
||||||
{
|
|
||||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
|
||||||
{
|
|
||||||
write!(formatter, "{:?}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::str::FromStr for ProofDirection
|
|
||||||
{
|
|
||||||
type Err = InvalidProofDirectionError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err>
|
|
||||||
{
|
|
||||||
match s
|
|
||||||
{
|
|
||||||
"forward" => Ok(ProofDirection::Forward),
|
|
||||||
"backward" => Ok(ProofDirection::Backward),
|
|
||||||
"both" => Ok(ProofDirection::Both),
|
|
||||||
_ => Err(InvalidProofDirectionError),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct ScopedFormula
|
|
||||||
{
|
|
||||||
pub free_variable_declarations: std::rc::Rc<foliage::VariableDeclarations>,
|
|
||||||
pub formula: foliage::Formula,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn existential_closure(scoped_formula: crate::ScopedFormula) -> foliage::Formula
|
|
||||||
{
|
|
||||||
match scoped_formula.free_variable_declarations.is_empty()
|
|
||||||
{
|
|
||||||
true => scoped_formula.formula,
|
|
||||||
false => foliage::Formula::exists(scoped_formula.free_variable_declarations,
|
|
||||||
Box::new(scoped_formula.formula)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn universal_closure(scoped_formula: crate::ScopedFormula) -> foliage::Formula
|
|
||||||
{
|
|
||||||
match scoped_formula.free_variable_declarations.is_empty()
|
|
||||||
{
|
|
||||||
true => scoped_formula.formula,
|
|
||||||
false => foliage::Formula::for_all(scoped_formula.free_variable_declarations,
|
|
||||||
Box::new(scoped_formula.formula)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*pub fn parse_predicate_declaration(input: &str)
|
|
||||||
-> Result<std::rc::Rc<foliage::PredicateDeclaration>, crate::Error>
|
|
||||||
{
|
|
||||||
let mut parts = input.split("/");
|
|
||||||
|
|
||||||
let name = parts.next().ok_or(crate::Error::new_parse_predicate_declaration())?;
|
|
||||||
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
let arity = match parts.next()
|
|
||||||
{
|
|
||||||
Some(arity)
|
|
||||||
=> usize::from_str(arity).map_err(|_| crate::Error::new_parse_predicate_declaration())?,
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
if parts.next().is_some()
|
|
||||||
{
|
|
||||||
return Err(crate::Error::new_parse_predicate_declaration());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(std::rc::Rc::new(foliage::PredicateDeclaration
|
|
||||||
{
|
|
||||||
name: name.to_string(),
|
|
||||||
arity,
|
|
||||||
}))
|
|
||||||
}*/
|
|
||||||
|
|
||||||
pub type InputConstantDeclarationDomains
|
|
||||||
= std::collections::BTreeMap<std::rc::Rc<foliage::FunctionDeclaration>, Domain>;
|
|
||||||
|
|
||||||
/*pub fn parse_constant_declaration(input: &str)
|
|
||||||
-> Result<(std::rc::Rc<foliage::FunctionDeclaration>, crate::Domain), crate::Error>
|
|
||||||
{
|
|
||||||
let mut parts = input.split(":");
|
|
||||||
|
|
||||||
let name = parts.next().ok_or(crate::Error::new_parse_constant_declaration())?.trim();
|
|
||||||
|
|
||||||
let domain = match parts.next()
|
|
||||||
{
|
|
||||||
None => crate::Domain::Program,
|
|
||||||
Some(value) => match value.trim()
|
|
||||||
{
|
|
||||||
"program" => crate::Domain::Program,
|
|
||||||
"integer" => crate::Domain::Integer,
|
|
||||||
_ => return Err(crate::Error::new_parse_constant_declaration()),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if parts.next().is_some()
|
|
||||||
{
|
|
||||||
return Err(crate::Error::new_parse_constant_declaration());
|
|
||||||
}
|
|
||||||
|
|
||||||
let constant_declaration = std::rc::Rc::new(foliage::FunctionDeclaration
|
|
||||||
{
|
|
||||||
name: name.to_string(),
|
|
||||||
arity: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok((constant_declaration, domain))
|
|
||||||
}*/
|
|
||||||
|
@@ -1,16 +1,15 @@
|
|||||||
pub(crate) fn is_term_arithmetic<C>(term: &foliage::Term, context: &C) -> Result<bool, crate::Error>
|
pub(crate) fn is_term_arithmetic(term: &crate::Term) -> Result<bool, crate::Error>
|
||||||
where
|
|
||||||
C: crate::traits::InputConstantDeclarationDomain
|
|
||||||
+ crate::traits::VariableDeclarationDomain
|
|
||||||
{
|
{
|
||||||
|
use crate::Term;
|
||||||
|
|
||||||
match term
|
match term
|
||||||
{
|
{
|
||||||
foliage::Term::Boolean(_)
|
Term::Boolean(_)
|
||||||
| foliage::Term::SpecialInteger(_)
|
| Term::SpecialInteger(_)
|
||||||
| foliage::Term::String(_)
|
| Term::String(_)
|
||||||
=> Ok(false),
|
=> Ok(false),
|
||||||
foliage::Term::Integer(_) => Ok(true),
|
Term::Integer(_) => Ok(true),
|
||||||
foliage::Term::Function(ref function) =>
|
Term::Function(ref function) =>
|
||||||
{
|
{
|
||||||
if !function.arguments.is_empty()
|
if !function.arguments.is_empty()
|
||||||
{
|
{
|
||||||
@@ -18,20 +17,17 @@ where
|
|||||||
crate::Error::new_unsupported_language_feature("functions with arguments"));
|
crate::Error::new_unsupported_language_feature("functions with arguments"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let domain = context.input_constant_declaration_domain(&function.declaration);
|
Ok(*function.declaration.domain.borrow() == crate::Domain::Integer)
|
||||||
|
|
||||||
Ok(domain == crate::Domain::Integer)
|
|
||||||
},
|
},
|
||||||
foliage::Term::Variable(foliage::Variable{ref declaration}) =>
|
Term::Variable(crate::Variable{ref declaration}) =>
|
||||||
match context.variable_declaration_domain(declaration)
|
match declaration.domain()?
|
||||||
{
|
{
|
||||||
Some(crate::Domain::Program) => Ok(false),
|
crate::Domain::Program => Ok(false),
|
||||||
Some(crate::Domain::Integer) => Ok(true),
|
crate::Domain::Integer => Ok(true),
|
||||||
None => Err(crate::Error::new_logic("unspecified variable declaration domain")),
|
|
||||||
},
|
},
|
||||||
foliage::Term::BinaryOperation(foliage::BinaryOperation{ref left, ref right, ..})
|
Term::BinaryOperation(crate::BinaryOperation{ref left, ref right, ..})
|
||||||
=> Ok(is_term_arithmetic(left, context)? && is_term_arithmetic(right, context)?),
|
=> Ok(is_term_arithmetic(left)? && is_term_arithmetic(right)?),
|
||||||
foliage::Term::UnaryOperation(foliage::UnaryOperation{ref argument, ..})
|
Term::UnaryOperation(crate::UnaryOperation{ref argument, ..})
|
||||||
=> is_term_arithmetic(argument, context),
|
=> is_term_arithmetic(argument),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
246
src/utils/autoname_variables.rs
Normal file
246
src/utils/autoname_variables.rs
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
struct IDs
|
||||||
|
{
|
||||||
|
program_variable_id: usize,
|
||||||
|
integer_variable_id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IDs
|
||||||
|
{
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self
|
||||||
|
{
|
||||||
|
program_variable_id: 1,
|
||||||
|
integer_variable_id: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_variable_name(variable_declaration: &crate::VariableDeclaration)
|
||||||
|
{
|
||||||
|
let domain = match variable_declaration.domain()
|
||||||
|
{
|
||||||
|
Ok(domain) => domain,
|
||||||
|
Err(_) => unreachable!("all variable domains should be assigned at this point"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ref mut variable_name = *variable_declaration.name.borrow_mut();
|
||||||
|
|
||||||
|
match variable_name
|
||||||
|
{
|
||||||
|
crate::VariableName::Generated(ref mut generated_variable_name) =>
|
||||||
|
generated_variable_name.id = None,
|
||||||
|
crate::VariableName::UserDefined(_) =>
|
||||||
|
*variable_name = crate::VariableName::Generated(
|
||||||
|
crate::GeneratedVariableName
|
||||||
|
{
|
||||||
|
domain,
|
||||||
|
id: None,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_variable_names_in_term(term: &mut crate::Term)
|
||||||
|
{
|
||||||
|
use foliage::Term;
|
||||||
|
|
||||||
|
match term
|
||||||
|
{
|
||||||
|
Term::BinaryOperation(ref mut binary_operation) =>
|
||||||
|
{
|
||||||
|
reset_variable_names_in_term(&mut *binary_operation.left);
|
||||||
|
reset_variable_names_in_term(&mut *binary_operation.right);
|
||||||
|
},
|
||||||
|
Term::Boolean(_)
|
||||||
|
| Term::Integer(_)
|
||||||
|
| Term::SpecialInteger(_)
|
||||||
|
| Term::String(_) => (),
|
||||||
|
Term::Function(ref mut function) =>
|
||||||
|
for mut argument in &mut function.arguments
|
||||||
|
{
|
||||||
|
reset_variable_names_in_term(&mut argument);
|
||||||
|
},
|
||||||
|
Term::UnaryOperation(ref mut unary_operation) =>
|
||||||
|
reset_variable_names_in_term(&mut *unary_operation.argument),
|
||||||
|
Term::Variable(ref mut variable) => reset_variable_name(&variable.declaration),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_variable_names_in_formula(formula: &mut crate::Formula)
|
||||||
|
{
|
||||||
|
use foliage::Formula;
|
||||||
|
|
||||||
|
match formula
|
||||||
|
{
|
||||||
|
Formula::And(ref mut arguments)
|
||||||
|
| Formula::IfAndOnlyIf(ref mut arguments)
|
||||||
|
| Formula::Or(ref mut arguments) =>
|
||||||
|
for argument in arguments
|
||||||
|
{
|
||||||
|
reset_variable_names_in_formula(argument);
|
||||||
|
},
|
||||||
|
Formula::Boolean(_) => (),
|
||||||
|
Formula::Compare(ref mut compare) =>
|
||||||
|
{
|
||||||
|
reset_variable_names_in_term(&mut *compare.left);
|
||||||
|
reset_variable_names_in_term(&mut *compare.right);
|
||||||
|
},
|
||||||
|
Formula::Exists(ref mut quantified_formula)
|
||||||
|
| Formula::ForAll(ref mut quantified_formula) =>
|
||||||
|
{
|
||||||
|
for ref parameter in &*quantified_formula.parameters
|
||||||
|
{
|
||||||
|
reset_variable_name(¶meter);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_variable_names_in_formula(&mut *quantified_formula.argument);
|
||||||
|
},
|
||||||
|
Formula::Implies(ref mut implies) =>
|
||||||
|
{
|
||||||
|
reset_variable_names_in_formula(&mut *implies.antecedent);
|
||||||
|
reset_variable_names_in_formula(&mut *implies.implication);
|
||||||
|
},
|
||||||
|
Formula::Not(ref mut argument) => reset_variable_names_in_formula(argument),
|
||||||
|
Formula::Predicate(ref mut predicate) =>
|
||||||
|
for mut argument in &mut predicate.arguments
|
||||||
|
{
|
||||||
|
reset_variable_names_in_term(&mut argument);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_variable_name(variable_declaration: &crate::VariableDeclaration, ids: &mut IDs)
|
||||||
|
{
|
||||||
|
match *variable_declaration.name.borrow_mut()
|
||||||
|
{
|
||||||
|
crate::VariableName::Generated(ref mut generated_variable_name) =>
|
||||||
|
{
|
||||||
|
if generated_variable_name.id.is_some()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match generated_variable_name.domain
|
||||||
|
{
|
||||||
|
crate::Domain::Program =>
|
||||||
|
{
|
||||||
|
generated_variable_name.id = Some(ids.program_variable_id);
|
||||||
|
ids.program_variable_id += 1;
|
||||||
|
},
|
||||||
|
crate::Domain::Integer =>
|
||||||
|
{
|
||||||
|
generated_variable_name.id = Some(ids.integer_variable_id);
|
||||||
|
ids.integer_variable_id += 1;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
crate::VariableName::UserDefined(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_variable_names_in_term(term: &mut crate::Term, ids: &mut IDs)
|
||||||
|
{
|
||||||
|
use foliage::Term;
|
||||||
|
|
||||||
|
match term
|
||||||
|
{
|
||||||
|
Term::BinaryOperation(ref mut binary_operation) =>
|
||||||
|
{
|
||||||
|
set_variable_names_in_term(&mut *binary_operation.left, ids);
|
||||||
|
set_variable_names_in_term(&mut *binary_operation.right, ids);
|
||||||
|
},
|
||||||
|
Term::Boolean(_)
|
||||||
|
| Term::Integer(_)
|
||||||
|
| Term::SpecialInteger(_)
|
||||||
|
| Term::String(_) => (),
|
||||||
|
Term::Function(ref mut function) =>
|
||||||
|
for mut argument in &mut function.arguments
|
||||||
|
{
|
||||||
|
set_variable_names_in_term(&mut argument, ids);
|
||||||
|
},
|
||||||
|
Term::UnaryOperation(ref mut unary_operation) =>
|
||||||
|
set_variable_names_in_term(&mut *unary_operation.argument, ids),
|
||||||
|
Term::Variable(ref mut variable) => set_variable_name(&variable.declaration, ids),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_variable_names_in_formula(formula: &mut crate::Formula, ids: &mut IDs)
|
||||||
|
{
|
||||||
|
use foliage::Formula;
|
||||||
|
|
||||||
|
match formula
|
||||||
|
{
|
||||||
|
Formula::And(ref mut arguments)
|
||||||
|
| Formula::IfAndOnlyIf(ref mut arguments)
|
||||||
|
| Formula::Or(ref mut arguments) =>
|
||||||
|
for argument in arguments
|
||||||
|
{
|
||||||
|
set_variable_names_in_formula(argument, ids);
|
||||||
|
},
|
||||||
|
Formula::Boolean(_) => (),
|
||||||
|
Formula::Compare(ref mut compare) =>
|
||||||
|
{
|
||||||
|
set_variable_names_in_term(&mut *compare.left, ids);
|
||||||
|
set_variable_names_in_term(&mut *compare.right, ids);
|
||||||
|
},
|
||||||
|
Formula::Exists(ref mut quantified_formula)
|
||||||
|
| Formula::ForAll(ref mut quantified_formula) =>
|
||||||
|
{
|
||||||
|
for ref parameter in &*quantified_formula.parameters
|
||||||
|
{
|
||||||
|
set_variable_name(¶meter, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_variable_names_in_formula(&mut *quantified_formula.argument, ids);
|
||||||
|
},
|
||||||
|
Formula::Implies(ref mut implies) =>
|
||||||
|
match implies.direction
|
||||||
|
{
|
||||||
|
foliage::ImplicationDirection::LeftToRight =>
|
||||||
|
{
|
||||||
|
set_variable_names_in_formula(&mut *implies.antecedent, ids);
|
||||||
|
set_variable_names_in_formula(&mut *implies.implication, ids);
|
||||||
|
},
|
||||||
|
foliage::ImplicationDirection::RightToLeft =>
|
||||||
|
{
|
||||||
|
set_variable_names_in_formula(&mut *implies.implication, ids);
|
||||||
|
set_variable_names_in_formula(&mut *implies.antecedent, ids);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Formula::Not(ref mut argument) => set_variable_names_in_formula(argument, ids),
|
||||||
|
Formula::Predicate(ref mut predicate) =>
|
||||||
|
for mut argument in &mut predicate.arguments
|
||||||
|
{
|
||||||
|
set_variable_names_in_term(&mut argument, ids);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn autoname_variables(formula: &mut crate::Formula)
|
||||||
|
{
|
||||||
|
// TODO: refactor, this is a bit hacky
|
||||||
|
reset_variable_names_in_formula(formula);
|
||||||
|
|
||||||
|
let mut ids = IDs::new();
|
||||||
|
|
||||||
|
set_variable_names_in_formula(formula, &mut ids);
|
||||||
|
|
||||||
|
// If there only exists exactly one program variable (which incremented the ID from 1 to 2),
|
||||||
|
// give it the special ID 0 on the second run
|
||||||
|
ids.program_variable_id = match ids.program_variable_id
|
||||||
|
{
|
||||||
|
2 => 0,
|
||||||
|
_ => 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// If there only exists exactly one integer variable (which incremented the ID from 1 to 2),
|
||||||
|
// give it the special ID 0 on the second run
|
||||||
|
ids.integer_variable_id = match ids.integer_variable_id
|
||||||
|
{
|
||||||
|
2 => 0,
|
||||||
|
_ => 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
reset_variable_names_in_formula(formula);
|
||||||
|
set_variable_names_in_formula(formula, &mut ids);
|
||||||
|
}
|
19
src/utils/closures.rs
Normal file
19
src/utils/closures.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
pub(crate) fn existential_closure(open_formula: crate::OpenFormula) -> crate::Formula
|
||||||
|
{
|
||||||
|
match open_formula.free_variable_declarations.is_empty()
|
||||||
|
{
|
||||||
|
true => open_formula.formula,
|
||||||
|
false => crate::Formula::exists(open_formula.free_variable_declarations,
|
||||||
|
Box::new(open_formula.formula)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn universal_closure(open_formula: crate::OpenFormula) -> crate::Formula
|
||||||
|
{
|
||||||
|
match open_formula.free_variable_declarations.is_empty()
|
||||||
|
{
|
||||||
|
true => open_formula.formula,
|
||||||
|
false => crate::Formula::for_all(open_formula.free_variable_declarations,
|
||||||
|
Box::new(open_formula.formula)),
|
||||||
|
}
|
||||||
|
}
|
245
src/utils/copy_formula.rs
Normal file
245
src/utils/copy_formula.rs
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
fn replace_variables_in_term(term: &mut crate::Term,
|
||||||
|
old_variable_declarations: &crate::VariableDeclarations,
|
||||||
|
new_variable_declarations: &crate::VariableDeclarations)
|
||||||
|
{
|
||||||
|
assert_eq!(old_variable_declarations.len(), new_variable_declarations.len());
|
||||||
|
|
||||||
|
use crate::Term;
|
||||||
|
|
||||||
|
match term
|
||||||
|
{
|
||||||
|
Term::BinaryOperation(binary_operation) =>
|
||||||
|
{
|
||||||
|
replace_variables_in_term(&mut binary_operation.left, old_variable_declarations,
|
||||||
|
new_variable_declarations);
|
||||||
|
replace_variables_in_term(&mut binary_operation.right, old_variable_declarations,
|
||||||
|
new_variable_declarations);
|
||||||
|
},
|
||||||
|
Term::Function(function) =>
|
||||||
|
for mut argument in &mut function.arguments
|
||||||
|
{
|
||||||
|
replace_variables_in_term(&mut argument, old_variable_declarations,
|
||||||
|
new_variable_declarations);
|
||||||
|
},
|
||||||
|
Term::UnaryOperation(unary_operation) =>
|
||||||
|
replace_variables_in_term(&mut unary_operation.argument, old_variable_declarations,
|
||||||
|
new_variable_declarations),
|
||||||
|
Term::Variable(variable) =>
|
||||||
|
if let Some(index) = old_variable_declarations.iter().enumerate()
|
||||||
|
.find_map(
|
||||||
|
|(index, variable_declaration)|
|
||||||
|
{
|
||||||
|
match *variable_declaration == variable.declaration
|
||||||
|
{
|
||||||
|
true => Some(index),
|
||||||
|
false => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
variable.declaration = std::rc::Rc::clone(&new_variable_declarations[index]);
|
||||||
|
},
|
||||||
|
Term::Boolean(_)
|
||||||
|
| Term::Integer(_)
|
||||||
|
| Term::SpecialInteger(_)
|
||||||
|
| Term::String(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_variables_in_formula(formula: &mut crate::Formula,
|
||||||
|
old_variable_declarations: &crate::VariableDeclarations,
|
||||||
|
new_variable_declarations: &crate::VariableDeclarations)
|
||||||
|
{
|
||||||
|
use crate::Formula;
|
||||||
|
|
||||||
|
match formula
|
||||||
|
{
|
||||||
|
Formula::And(arguments)
|
||||||
|
| Formula::IfAndOnlyIf(arguments)
|
||||||
|
| Formula::Or(arguments) =>
|
||||||
|
for argument in arguments
|
||||||
|
{
|
||||||
|
replace_variables_in_formula(argument, old_variable_declarations,
|
||||||
|
new_variable_declarations);
|
||||||
|
},
|
||||||
|
Formula::Compare(compare) =>
|
||||||
|
{
|
||||||
|
replace_variables_in_term(&mut compare.left, old_variable_declarations,
|
||||||
|
new_variable_declarations);
|
||||||
|
replace_variables_in_term(&mut compare.right, old_variable_declarations,
|
||||||
|
new_variable_declarations);
|
||||||
|
},
|
||||||
|
Formula::Exists(quantified_formula)
|
||||||
|
| Formula::ForAll(quantified_formula) =>
|
||||||
|
replace_variables_in_formula(&mut quantified_formula.argument,
|
||||||
|
old_variable_declarations, new_variable_declarations),
|
||||||
|
Formula::Implies(implies) =>
|
||||||
|
{
|
||||||
|
replace_variables_in_formula(&mut implies.antecedent, old_variable_declarations,
|
||||||
|
new_variable_declarations);
|
||||||
|
replace_variables_in_formula(&mut implies.implication, old_variable_declarations,
|
||||||
|
new_variable_declarations);
|
||||||
|
},
|
||||||
|
Formula::Not(argument) =>
|
||||||
|
replace_variables_in_formula(argument, old_variable_declarations,
|
||||||
|
new_variable_declarations),
|
||||||
|
Formula::Predicate(predicate) =>
|
||||||
|
for mut argument in &mut predicate.arguments
|
||||||
|
{
|
||||||
|
replace_variables_in_term(&mut argument, old_variable_declarations,
|
||||||
|
new_variable_declarations);
|
||||||
|
},
|
||||||
|
Formula::Boolean(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_variable_in_term_with_term(term: &mut crate::Term,
|
||||||
|
variable_declaration: &crate::VariableDeclaration, replacement_term: &crate::Term)
|
||||||
|
{
|
||||||
|
use crate::Term;
|
||||||
|
|
||||||
|
match term
|
||||||
|
{
|
||||||
|
Term::BinaryOperation(binary_operation) =>
|
||||||
|
{
|
||||||
|
replace_variable_in_term_with_term(&mut binary_operation.left, variable_declaration,
|
||||||
|
replacement_term);
|
||||||
|
replace_variable_in_term_with_term(&mut binary_operation.right, variable_declaration,
|
||||||
|
replacement_term);
|
||||||
|
},
|
||||||
|
Term::Function(function) =>
|
||||||
|
for mut argument in &mut function.arguments
|
||||||
|
{
|
||||||
|
replace_variable_in_term_with_term(&mut argument, variable_declaration,
|
||||||
|
replacement_term);
|
||||||
|
},
|
||||||
|
Term::UnaryOperation(unary_operation) =>
|
||||||
|
replace_variable_in_term_with_term(&mut unary_operation.argument, variable_declaration,
|
||||||
|
replacement_term),
|
||||||
|
Term::Variable(variable) =>
|
||||||
|
if *variable.declaration == *variable_declaration
|
||||||
|
{
|
||||||
|
*term = copy_term(replacement_term);
|
||||||
|
},
|
||||||
|
Term::Boolean(_)
|
||||||
|
| Term::Integer(_)
|
||||||
|
| Term::SpecialInteger(_)
|
||||||
|
| Term::String(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn replace_variable_in_formula_with_term(formula: &mut crate::Formula,
|
||||||
|
variable_declaration: &crate::VariableDeclaration, replacement_term: &crate::Term)
|
||||||
|
{
|
||||||
|
use crate::Formula;
|
||||||
|
|
||||||
|
match formula
|
||||||
|
{
|
||||||
|
Formula::And(arguments)
|
||||||
|
| Formula::IfAndOnlyIf(arguments)
|
||||||
|
| Formula::Or(arguments) =>
|
||||||
|
for argument in arguments
|
||||||
|
{
|
||||||
|
replace_variable_in_formula_with_term(argument, variable_declaration,
|
||||||
|
replacement_term);
|
||||||
|
},
|
||||||
|
Formula::Compare(compare) =>
|
||||||
|
{
|
||||||
|
replace_variable_in_term_with_term(&mut compare.left, variable_declaration,
|
||||||
|
replacement_term);
|
||||||
|
replace_variable_in_term_with_term(&mut compare.right, variable_declaration,
|
||||||
|
replacement_term);
|
||||||
|
},
|
||||||
|
Formula::Exists(quantified_formula)
|
||||||
|
| Formula::ForAll(quantified_formula) =>
|
||||||
|
replace_variable_in_formula_with_term(&mut quantified_formula.argument,
|
||||||
|
variable_declaration, replacement_term),
|
||||||
|
Formula::Implies(implies) =>
|
||||||
|
{
|
||||||
|
replace_variable_in_formula_with_term(&mut implies.antecedent, variable_declaration,
|
||||||
|
replacement_term);
|
||||||
|
replace_variable_in_formula_with_term(&mut implies.implication, variable_declaration,
|
||||||
|
replacement_term);
|
||||||
|
},
|
||||||
|
Formula::Not(argument) =>
|
||||||
|
replace_variable_in_formula_with_term(argument, variable_declaration, replacement_term),
|
||||||
|
Formula::Predicate(predicate) =>
|
||||||
|
for mut argument in &mut predicate.arguments
|
||||||
|
{
|
||||||
|
replace_variable_in_term_with_term(&mut argument, variable_declaration,
|
||||||
|
replacement_term);
|
||||||
|
},
|
||||||
|
Formula::Boolean(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn copy_term(term: &crate::Term) -> crate::Term
|
||||||
|
{
|
||||||
|
use crate::Term;
|
||||||
|
|
||||||
|
match term
|
||||||
|
{
|
||||||
|
Term::BinaryOperation(binary_operation) =>
|
||||||
|
Term::binary_operation(binary_operation.operator,
|
||||||
|
Box::new(copy_term(&binary_operation.left)),
|
||||||
|
Box::new(copy_term(&binary_operation.right))),
|
||||||
|
Term::Boolean(value) => Term::boolean(*value),
|
||||||
|
Term::Function(function) => Term::function(std::rc::Rc::clone(&function.declaration),
|
||||||
|
function.arguments.iter().map(|argument| copy_term(argument)).collect()),
|
||||||
|
Term::Integer(value) => Term::integer(*value),
|
||||||
|
Term::SpecialInteger(value) => Term::special_integer(*value),
|
||||||
|
Term::String(value) => Term::string(value.clone()),
|
||||||
|
Term::UnaryOperation(unary_operation) => Term::unary_operation(unary_operation.operator,
|
||||||
|
Box::new(copy_term(&unary_operation.argument))),
|
||||||
|
Term::Variable(variable) => Term::variable(std::rc::Rc::clone(&variable.declaration)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_quantified_formula(quantified_expression: &crate::QuantifiedFormula)
|
||||||
|
-> crate::QuantifiedFormula
|
||||||
|
{
|
||||||
|
let copy_parameters =
|
||||||
|
quantified_expression.parameters.iter()
|
||||||
|
// TODO: check correctness of clone implementation
|
||||||
|
.map(|x| x.clone())
|
||||||
|
.collect();
|
||||||
|
let copy_parameters = std::rc::Rc::new(copy_parameters);
|
||||||
|
|
||||||
|
let mut copy_argument = copy_formula(&quantified_expression.argument);
|
||||||
|
|
||||||
|
replace_variables_in_formula(&mut copy_argument, &quantified_expression.parameters,
|
||||||
|
©_parameters);
|
||||||
|
|
||||||
|
crate::QuantifiedFormula::new(copy_parameters, Box::new(copy_argument))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn copy_formula(formula: &crate::Formula) -> crate::Formula
|
||||||
|
{
|
||||||
|
use crate::Formula;
|
||||||
|
|
||||||
|
match formula
|
||||||
|
{
|
||||||
|
Formula::And(arguments) =>
|
||||||
|
Formula::and(arguments.iter().map(|argument| copy_formula(argument)).collect()),
|
||||||
|
Formula::Boolean(value) => Formula::boolean(*value),
|
||||||
|
Formula::Compare(compare) =>
|
||||||
|
Formula::compare(compare.operator, Box::new(copy_term(&compare.left)),
|
||||||
|
Box::new(copy_term(&compare.right))),
|
||||||
|
Formula::Exists(quantified_formula) =>
|
||||||
|
Formula::Exists(copy_quantified_formula(quantified_formula)),
|
||||||
|
Formula::ForAll(quantified_formula) =>
|
||||||
|
Formula::ForAll(copy_quantified_formula(quantified_formula)),
|
||||||
|
Formula::IfAndOnlyIf(arguments) =>
|
||||||
|
Formula::if_and_only_if(
|
||||||
|
arguments.iter().map(|argument| copy_formula(argument)).collect()),
|
||||||
|
Formula::Implies(implies) =>
|
||||||
|
Formula::implies(implies.direction, Box::new(copy_formula(&implies.antecedent)),
|
||||||
|
Box::new(copy_formula(&implies.implication))),
|
||||||
|
Formula::Not(argument) => Formula::not(Box::new(copy_formula(&argument))),
|
||||||
|
Formula::Or(arguments) =>
|
||||||
|
Formula::or(arguments.iter().map(|argument| copy_formula(argument)).collect()),
|
||||||
|
Formula::Predicate(predicate) =>
|
||||||
|
Formula::predicate(std::rc::Rc::clone(&predicate.declaration),
|
||||||
|
predicate.arguments.iter().map(|argument| copy_term(argument)).collect()),
|
||||||
|
}
|
||||||
|
}
|
36
src/utils/fold_predicates.rs
Normal file
36
src/utils/fold_predicates.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
pub(crate) fn fold_predicates<B, F>(formula: &crate::Formula, mut accumulator: B, functor: &mut F)
|
||||||
|
-> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, &crate::Predicate) -> B,
|
||||||
|
{
|
||||||
|
use crate::Formula;
|
||||||
|
|
||||||
|
match formula
|
||||||
|
{
|
||||||
|
Formula::And(arguments)
|
||||||
|
| Formula::IfAndOnlyIf(arguments)
|
||||||
|
| Formula::Or(arguments) =>
|
||||||
|
{
|
||||||
|
for argument in arguments
|
||||||
|
{
|
||||||
|
accumulator = fold_predicates(argument, accumulator, functor);
|
||||||
|
}
|
||||||
|
|
||||||
|
accumulator
|
||||||
|
},
|
||||||
|
Formula::Boolean(_)
|
||||||
|
| Formula::Compare(_) => accumulator,
|
||||||
|
Formula::Exists(quantified_expression)
|
||||||
|
| Formula::ForAll(quantified_expression) =>
|
||||||
|
fold_predicates(&quantified_expression.argument, accumulator, functor),
|
||||||
|
Formula::Implies(implies) =>
|
||||||
|
{
|
||||||
|
accumulator = fold_predicates(&implies.antecedent, accumulator, functor);
|
||||||
|
accumulator = fold_predicates(&implies.implication, accumulator, functor);
|
||||||
|
|
||||||
|
accumulator
|
||||||
|
},
|
||||||
|
Formula::Not(argument) => fold_predicates(argument, accumulator, functor),
|
||||||
|
Formula::Predicate(predicate) => functor(accumulator, &predicate),
|
||||||
|
}
|
||||||
|
}
|
25
src/utils/formula_contains_predicate.rs
Normal file
25
src/utils/formula_contains_predicate.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
pub(crate) fn formula_contains_predicate(formula: &crate::Formula,
|
||||||
|
predicate_declaration: &crate::PredicateDeclaration)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
use crate::Formula;
|
||||||
|
|
||||||
|
match formula
|
||||||
|
{
|
||||||
|
Formula::And(arguments)
|
||||||
|
| Formula::IfAndOnlyIf(arguments)
|
||||||
|
| Formula::Or(arguments) =>
|
||||||
|
arguments.iter().any(
|
||||||
|
|argument| formula_contains_predicate(argument, predicate_declaration)),
|
||||||
|
Formula::Boolean(_)
|
||||||
|
| Formula::Compare(_) => false,
|
||||||
|
Formula::Exists(quantified_expression)
|
||||||
|
| Formula::ForAll(quantified_expression) =>
|
||||||
|
formula_contains_predicate(&quantified_expression.argument, predicate_declaration),
|
||||||
|
Formula::Implies(implies) =>
|
||||||
|
formula_contains_predicate(&implies.antecedent, predicate_declaration)
|
||||||
|
|| formula_contains_predicate(&implies.implication, predicate_declaration),
|
||||||
|
Formula::Not(argument) => formula_contains_predicate(argument, predicate_declaration),
|
||||||
|
Formula::Predicate(predicate) => &*predicate.declaration == predicate_declaration,
|
||||||
|
}
|
||||||
|
}
|
21
src/utils/variables_in_terms.rs
Normal file
21
src/utils/variables_in_terms.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
pub(crate) fn term_contains_variable(term: &crate::Term,
|
||||||
|
variable_declaration: &crate::VariableDeclaration)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
use crate::Term;
|
||||||
|
|
||||||
|
match term
|
||||||
|
{
|
||||||
|
Term::BinaryOperation(binary_operation) =>
|
||||||
|
term_contains_variable(&binary_operation.left, variable_declaration)
|
||||||
|
|| term_contains_variable(&binary_operation.right, variable_declaration),
|
||||||
|
Term::Boolean(_)
|
||||||
|
| Term::Function(_)
|
||||||
|
| Term::Integer(_)
|
||||||
|
| Term::SpecialInteger(_)
|
||||||
|
| Term::String(_) => false,
|
||||||
|
Term::UnaryOperation(unary_operation) =>
|
||||||
|
term_contains_variable(&unary_operation.argument, variable_declaration),
|
||||||
|
Term::Variable(variable) => *variable.declaration == *variable_declaration,
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user