add-only set of access paths. To make common operations efficient (namely, add, join, and widen), the set is allowed to contain elements whose concretization is redundant (e.g., x* and x.f). these redundancies can be eliminated by expressing the set in its canonical form via a call to `normalize`. however, `normalize` is quadratic in the size of the set, so it should be used sparingly (recommendation: only before computing a summary based on the access path set)

`include AbstractDomain.WithBottom`
`include AbstractDomain.S`
`type astate`````
`val (<=) : lhs:astate ‑> rhs:astate ‑> bool`

the partial order induced by join

`val join : astate ‑> astate ‑> astate`
`val widen : prev:astate ‑> next:astate ‑> num_iters:int ‑> astate`
`val pp : InferModules.AbstractDomain.F.formatter ‑> astate ‑> unit`
`val empty : astate`

The bottom value of the domain. Naming it empty instead of bottom helps to bind the empty value for sets and maps to the natural definition for bottom

`val is_empty : astate ‑> bool`

Return true if this is the bottom value

`val of_list : InferIR.AccessPath.Abs.t list ‑> astate`
`val mem : InferIR.AccessPath.Abs.t ‑> astate ‑> bool`

return true if \gamma({ap}) \subseteq \gamma(aps). note: this is worst-case linear in the size of the set

`val mem_fuzzy : InferIR.AccessPath.Abs.t ‑> astate ‑> bool`

more permissive version of `mem`; return true if \gamma({a}) \cap \gamma(aps) != {}. note: this is worst-case linear in the size of the set

`val add : InferIR.AccessPath.Abs.t ‑> astate ‑> astate`
`val normalize : astate ‑> astate`

simplify an access path set to its canonical representation by eliminating redundancies between (1) pairs of abstracted access_paths, and (2) exact access paths and abstracted access paths. warning: this is quadratic in the size of the set! use sparingly