[sledge] Revise Arith.map to use maximal non-interpreted subterms

Summary:
Change Arith.map to not descend through non-interpreted arithmetic
operators. For example, in `2×(x × y) + 3×z + 4`, `map ~f` will apply
`f` to the subterms `x × y` and `z`, but not `x` or `y`.

The logical notion of "subterm" that is needed by the solver does not
coincide with the representation. This is essentially due to not
"flattening" or "purifying" terms.  That is, traditionally `x × y`
would not be permitted as an indeterminate of a polynomial. Instead, a
new variable would need to be introduced: `v = x × y` and then the
polynomial would be expressed as `2×v + 3×z + 4`. Taking maximal
non-interpreted subterms as the definition of "subterm" results in
subterms in the non-flattened representation that are equivalent to
those that would result from flattening the representation.

Reviewed By: jvillard

Differential Revision: D24746235

fbshipit-source-id: d8fcf46a1
master
Josh Berdine 4 years ago committed by Facebook GitHub Bot
parent 6f4dcfbdd9
commit 1a4363627c

@ -178,6 +178,15 @@ struct
| _ -> Uninterpreted )
| `Many -> Interpreted
let is_noninterpreted poly =
match Sum.only_elt poly with
| Some (mono, _) -> (
match Prod.classify mono with
| `Zero -> false
| `One (_, n) -> n <> 1
| `Many -> true )
| None -> false
let get_const poly =
match Sum.classify poly with
| `Zero -> Some Q.zero
@ -193,7 +202,6 @@ struct
module CM = struct
type t = Q.t * Prod.t
let one = (Q.one, Mono.one)
let mul (c1, m1) (c2, m2) = (Q.mul c1 c2, Mono.mul m1 m2)
(** Monomials [Mono.t] have [trm] indeterminates, which include, via
@ -232,6 +240,12 @@ struct
|> check invariant
end
(** Embed a monomial into a term, flattening if possible *)
let trm_of_mono mono =
match Mono.get_trm mono with
| Some trm -> trm
| None -> Embed.to_trm (Sum.of_ mono Q.one)
(** Embed a term into a polynomial, by projecting a polynomial out of
the term if possible *)
let trm trm =
@ -272,21 +286,17 @@ struct
~call:(fun {pf} -> pf "%a" pp poly)
~retn:(fun {pf} -> pf "%a" pp)
@@ fun () ->
let p, p' = (poly, Sum.empty) in
let p, p' =
Sum.fold poly (p, p') ~f:(fun mono coeff (p, p') ->
let m, cm' = (mono, CM.one) in
let m, cm' =
Prod.fold mono (m, cm') ~f:(fun trm power (m, cm') ->
let trm' = f trm in
if trm == trm' then (m, cm')
else
(Prod.remove trm m, CM.mul cm' (CM.of_trm trm' ~power)) )
in
( Sum.remove mono p
, Sum.union p' (CM.to_poly (CM.mul (coeff, m) cm')) ) )
in
Sum.union p p' |> check invariant
( if is_noninterpreted poly then poly
else
let p, p' =
Sum.fold poly (poly, Sum.empty) ~f:(fun mono coeff (p, p') ->
let e = trm_of_mono mono in
let e' = f e in
if e == e' then (p, p')
else (Sum.remove mono p, Sum.union p' (mulc coeff (trm e'))) )
in
Sum.union p p' )
|> check invariant
(* traverse *)

@ -57,10 +57,8 @@ module type S = sig
coefficients in [p] and [n] are non-negative. *)
val map : t -> f:(trm -> trm) -> t
(** [map ~f a] is [a] with each indeterminate transformed by [f]. Viewing
[a] as a polynomial,
[map ~f (Σ c × Π x^p)] is
[Σ c × Π (f x)^p]. *)
(** [map ~f a] is [a] with each maximal non-interpreted subterm
transformed by [f]. *)
(** Traverse *)

Loading…
Cancel
Save