Reviewed By: ngorogiannis Differential Revision: D26250525 fbshipit-source-id: 5a61bc4ffmaster
parent
daaff7ad01
commit
e284b06e5b
@ -0,0 +1,78 @@
|
|||||||
|
(*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** Renaming Substitutions: injective maps from variables to variables *)
|
||||||
|
|
||||||
|
include Subst_intf
|
||||||
|
|
||||||
|
module Make (Var : VAR) = struct
|
||||||
|
module Set = Var.Set
|
||||||
|
module Map = Var.Map
|
||||||
|
|
||||||
|
type t = Var.t Map.t [@@deriving compare, equal, sexp_of]
|
||||||
|
type x = {sub: t; dom: Set.t; rng: Set.t}
|
||||||
|
|
||||||
|
let t_of_sexp = Map.t_of_sexp Var.t_of_sexp
|
||||||
|
let pp = Map.pp Var.pp Var.pp
|
||||||
|
|
||||||
|
let invariant s =
|
||||||
|
let@ () = Invariant.invariant [%here] s [%sexp_of: t] in
|
||||||
|
let domain, range =
|
||||||
|
Map.fold s (Set.empty, Set.empty)
|
||||||
|
~f:(fun ~key ~data (domain, range) ->
|
||||||
|
(* substs are injective *)
|
||||||
|
assert (not (Set.mem data range)) ;
|
||||||
|
(Set.add key domain, Set.add data range) )
|
||||||
|
in
|
||||||
|
assert (Set.disjoint domain range)
|
||||||
|
|
||||||
|
let empty = Map.empty
|
||||||
|
let is_empty = Map.is_empty
|
||||||
|
|
||||||
|
let freshen vs ~wrt =
|
||||||
|
let dom = Set.inter wrt vs in
|
||||||
|
( if Set.is_empty dom then
|
||||||
|
({sub= empty; dom= Set.empty; rng= Set.empty}, wrt)
|
||||||
|
else
|
||||||
|
let wrt = Set.union wrt vs in
|
||||||
|
let sub, rng, wrt =
|
||||||
|
Set.fold dom (empty, Set.empty, wrt) ~f:(fun x (sub, rng, wrt) ->
|
||||||
|
let x', wrt = Var.freshen x ~wrt in
|
||||||
|
let sub = Map.add_exn ~key:x ~data:x' sub in
|
||||||
|
let rng = Set.add x' rng in
|
||||||
|
(sub, rng, wrt) )
|
||||||
|
in
|
||||||
|
({sub; dom; rng}, wrt) )
|
||||||
|
|> check (fun ({sub; _}, _) -> invariant sub)
|
||||||
|
|
||||||
|
let fold sub z ~f = Map.fold ~f:(fun ~key ~data -> f key data) sub z
|
||||||
|
let domain sub = Set.of_iter (Map.keys sub)
|
||||||
|
let range sub = Set.of_iter (Map.values sub)
|
||||||
|
|
||||||
|
let invert sub =
|
||||||
|
Map.fold sub empty ~f:(fun ~key ~data sub' ->
|
||||||
|
Map.add_exn ~key:data ~data:key sub' )
|
||||||
|
|> check invariant
|
||||||
|
|
||||||
|
let restrict_dom sub0 vs =
|
||||||
|
Map.fold sub0 {sub= sub0; dom= Set.empty; rng= Set.empty}
|
||||||
|
~f:(fun ~key ~data z ->
|
||||||
|
let rng = Set.add data z.rng in
|
||||||
|
if Set.mem key vs then {z with dom= Set.add key z.dom; rng}
|
||||||
|
else (
|
||||||
|
assert (
|
||||||
|
(* all substs are injective, so the current mapping is the only
|
||||||
|
one that can cause [data] to be in [rng] *)
|
||||||
|
(not (Set.mem data (range (Map.remove key sub0))))
|
||||||
|
|| violates invariant sub0 ) ;
|
||||||
|
{z with sub= Map.remove key z.sub; rng} ) )
|
||||||
|
|> check (fun {sub; dom; rng} ->
|
||||||
|
assert (Set.equal dom (domain sub)) ;
|
||||||
|
assert (Set.equal rng (range sub0)) )
|
||||||
|
|
||||||
|
let apply sub v = Map.find v sub |> Option.value ~default:v
|
||||||
|
end
|
@ -0,0 +1,46 @@
|
|||||||
|
(*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*)
|
||||||
|
|
||||||
|
(** Renaming Substitutions: injective maps from variables to variables *)
|
||||||
|
|
||||||
|
module type VAR = sig
|
||||||
|
type t [@@deriving compare, equal, sexp]
|
||||||
|
|
||||||
|
val pp : t pp
|
||||||
|
|
||||||
|
module Map : sig
|
||||||
|
include Map.S with type key := t
|
||||||
|
|
||||||
|
val t_of_sexp : (Sexp.t -> 'a) -> Sexp.t -> 'a t
|
||||||
|
end
|
||||||
|
|
||||||
|
module Set : Set.S with type elt := t
|
||||||
|
|
||||||
|
val freshen : t -> wrt:Set.t -> t * Set.t
|
||||||
|
end
|
||||||
|
|
||||||
|
module type S = sig
|
||||||
|
type var
|
||||||
|
type set
|
||||||
|
type t [@@deriving compare, equal, sexp]
|
||||||
|
type x = {sub: t; dom: set; rng: set}
|
||||||
|
|
||||||
|
val pp : t pp
|
||||||
|
val empty : t
|
||||||
|
val freshen : set -> wrt:set -> x * set
|
||||||
|
val invert : t -> t
|
||||||
|
|
||||||
|
val restrict_dom : t -> set -> x
|
||||||
|
(** restrict the domain of a substitution to a set, and yield the range of
|
||||||
|
the unrestricted substitution *)
|
||||||
|
|
||||||
|
val is_empty : t -> bool
|
||||||
|
val domain : t -> set
|
||||||
|
val range : t -> set
|
||||||
|
val fold : t -> 's -> f:(var -> var -> 's -> 's) -> 's
|
||||||
|
val apply : t -> var -> var
|
||||||
|
end
|
@ -1,129 +0,0 @@
|
|||||||
(*
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*)
|
|
||||||
|
|
||||||
open Var_intf
|
|
||||||
|
|
||||||
(** Variables, parameterized over their representation *)
|
|
||||||
module Make (T : REPR) = struct
|
|
||||||
module T = struct
|
|
||||||
include T
|
|
||||||
|
|
||||||
type strength = t -> [`Universal | `Existential | `Anonymous] option
|
|
||||||
|
|
||||||
let ppx strength ppf v =
|
|
||||||
let id = id v in
|
|
||||||
let name = name v in
|
|
||||||
if id < 0 then Trace.pp_styled `Bold "%%%s!%i" ppf name (-id)
|
|
||||||
else
|
|
||||||
match strength v with
|
|
||||||
| None -> Format.fprintf ppf "%%%s_%i" name id
|
|
||||||
| Some `Universal -> Trace.pp_styled `Bold "%%%s_%i" ppf name id
|
|
||||||
| Some `Existential -> Trace.pp_styled `Cyan "%%%s_%i" ppf name id
|
|
||||||
| Some `Anonymous -> Trace.pp_styled `Cyan "_" ppf
|
|
||||||
|
|
||||||
let pp = ppx (fun _ -> None)
|
|
||||||
end
|
|
||||||
|
|
||||||
include T
|
|
||||||
|
|
||||||
module Map = struct
|
|
||||||
include NS.Map.Make (T)
|
|
||||||
include Provide_of_sexp (T)
|
|
||||||
end
|
|
||||||
|
|
||||||
module Set = struct
|
|
||||||
module S = NS.Set.Make (T)
|
|
||||||
include S
|
|
||||||
include Provide_of_sexp (T)
|
|
||||||
include Provide_pp (T)
|
|
||||||
|
|
||||||
let ppx strength vs = S.pp_full (ppx strength) vs
|
|
||||||
|
|
||||||
let pp_xs fs xs =
|
|
||||||
if not (is_empty xs) then
|
|
||||||
Format.fprintf fs "@<2>∃ @[%a@] .@;<1 2>" pp xs
|
|
||||||
end
|
|
||||||
|
|
||||||
let fresh name ~wrt =
|
|
||||||
let max =
|
|
||||||
match Set.max_elt wrt with None -> 0 | Some m -> max 0 (id m)
|
|
||||||
in
|
|
||||||
let x' = make ~id:(max + 1) ~name in
|
|
||||||
(x', Set.add x' wrt)
|
|
||||||
|
|
||||||
let program ?(name = "") ~id =
|
|
||||||
assert (id > 0) ;
|
|
||||||
make ~id:(-id) ~name
|
|
||||||
|
|
||||||
let identified ~name ~id = make ~id ~name
|
|
||||||
|
|
||||||
(** Variable renaming substitutions *)
|
|
||||||
module Subst = struct
|
|
||||||
type t = T.t Map.t [@@deriving compare, equal, sexp_of]
|
|
||||||
type x = {sub: t; dom: Set.t; rng: Set.t}
|
|
||||||
|
|
||||||
let t_of_sexp = Map.t_of_sexp t_of_sexp
|
|
||||||
let pp = Map.pp pp pp
|
|
||||||
|
|
||||||
let invariant s =
|
|
||||||
let@ () = Invariant.invariant [%here] s [%sexp_of: t] in
|
|
||||||
let domain, range =
|
|
||||||
Map.fold s (Set.empty, Set.empty)
|
|
||||||
~f:(fun ~key ~data (domain, range) ->
|
|
||||||
(* substs are injective *)
|
|
||||||
assert (not (Set.mem data range)) ;
|
|
||||||
(Set.add key domain, Set.add data range) )
|
|
||||||
in
|
|
||||||
assert (Set.disjoint domain range)
|
|
||||||
|
|
||||||
let empty = Map.empty
|
|
||||||
let is_empty = Map.is_empty
|
|
||||||
|
|
||||||
let freshen vs ~wrt =
|
|
||||||
let dom = Set.inter wrt vs in
|
|
||||||
( if Set.is_empty dom then
|
|
||||||
({sub= empty; dom= Set.empty; rng= Set.empty}, wrt)
|
|
||||||
else
|
|
||||||
let wrt = Set.union wrt vs in
|
|
||||||
let sub, rng, wrt =
|
|
||||||
Set.fold dom (empty, Set.empty, wrt) ~f:(fun x (sub, rng, wrt) ->
|
|
||||||
let x', wrt = fresh (name x) ~wrt in
|
|
||||||
let sub = Map.add_exn ~key:x ~data:x' sub in
|
|
||||||
let rng = Set.add x' rng in
|
|
||||||
(sub, rng, wrt) )
|
|
||||||
in
|
|
||||||
({sub; dom; rng}, wrt) )
|
|
||||||
|> check (fun ({sub; _}, _) -> invariant sub)
|
|
||||||
|
|
||||||
let fold sub z ~f = Map.fold ~f:(fun ~key ~data -> f key data) sub z
|
|
||||||
let domain sub = Set.of_iter (Map.keys sub)
|
|
||||||
let range sub = Set.of_iter (Map.values sub)
|
|
||||||
|
|
||||||
let invert sub =
|
|
||||||
Map.fold sub empty ~f:(fun ~key ~data sub' ->
|
|
||||||
Map.add_exn ~key:data ~data:key sub' )
|
|
||||||
|> check invariant
|
|
||||||
|
|
||||||
let restrict_dom sub0 vs =
|
|
||||||
Map.fold sub0 {sub= sub0; dom= Set.empty; rng= Set.empty}
|
|
||||||
~f:(fun ~key ~data z ->
|
|
||||||
let rng = Set.add data z.rng in
|
|
||||||
if Set.mem key vs then {z with dom= Set.add key z.dom; rng}
|
|
||||||
else (
|
|
||||||
assert (
|
|
||||||
(* all substs are injective, so the current mapping is the
|
|
||||||
only one that can cause [data] to be in [rng] *)
|
|
||||||
(not (Set.mem data (range (Map.remove key sub0))))
|
|
||||||
|| violates invariant sub0 ) ;
|
|
||||||
{z with sub= Map.remove key z.sub; rng} ) )
|
|
||||||
|> check (fun {sub; dom; rng} ->
|
|
||||||
assert (Set.equal dom (domain sub)) ;
|
|
||||||
assert (Set.equal rng (range sub0)) )
|
|
||||||
|
|
||||||
let apply sub v = Map.find v sub |> Option.value ~default:v
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in new issue