Skip to content

Commit a043ad7

Browse files
committed
restrict def. of partial adjoints
1 parent 532063e commit a043ad7

File tree

3 files changed

+43
-56
lines changed

3 files changed

+43
-56
lines changed

ocaml/typing/mode.ml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,10 @@ module Lattices_mono = struct
10491049
let g' = left_adjoint mid g in
10501050
Compose (g', f')
10511051
| Join_with c -> Subtract c
1052-
| Meet_with _ -> Id
1052+
| Meet_with _c ->
1053+
(* The downward closure of [Meet_with c]'s image is all [x <= c].
1054+
For those, [x <= meet c y] is equivalent to [x <= y]. *)
1055+
Id
10531056
| Imply c -> Meet_with c
10541057
| Comonadic_to_monadic _ -> Monadic_to_comonadic_min
10551058
| Monadic_to_comonadic_max -> Comonadic_to_monadic dst
@@ -1077,7 +1080,10 @@ module Lattices_mono = struct
10771080
Compose (g', f')
10781081
| Meet_with c -> Imply c
10791082
| Subtract c -> Join_with c
1080-
| Join_with _ -> Id
1083+
| Join_with _c ->
1084+
(* The upward closure of [Join_with c]'s image is all [x >= c].
1085+
For those, [join c y <= x] is equivalent to [y <= x]. *)
1086+
Id
10811087
| Comonadic_to_monadic _ -> Monadic_to_comonadic_max
10821088
| Monadic_to_comonadic_min -> Comonadic_to_monadic dst
10831089
| Local_to_regional -> Regional_to_local

ocaml/typing/solver.ml

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -311,40 +311,16 @@ module Solver_mono (C : Lattices_mono) = struct
311311
type a l.
312312
log:_ -> a C.obj -> a -> (a, l * allowed) morphvar -> (unit, a) Result.t =
313313
fun ~log obj a (Amorphvar (v, f) as mv) ->
314-
(* Requested [a <= f v], therefore [f' a <= v], where [f'] is the left
315-
adjoint of [f]. We should just apply [f'] to [a] and use that to
316-
constrain [v].
317-
318-
However, we aim to support a wider of notion of adjunctions (see
319-
[solver_intf.mli] for context). Say [f : B' -> A'] and [f' : A' -> B'].
320-
Note that [f' a] is known to be well-defined only if [a \in A] where [A]
321-
is some convex sublattice of [A'].
322-
323-
Note that we don't request the [A] of [f] from [Lattices_mono] for
324-
simplicity. Instead, note that we need to check [a] against [f v] anyway,
325-
and the bound of the latter is a subset of [A]. Therefore, once we make
326-
sure [a] is within the bound of [f v], we are free to apply [f'] to [a].
327-
Concretely:
328-
329-
1. If [a <= (f v).lower], immediately succeed
330-
2. If not [a <= (f v).upper], immediately fail
331-
3. Note that at this point, we still can't ensure that [a >= (f v).lower].
332-
(We don't assume total ordering, for best generality)
333-
Therefore, we set [a] to [join a (f v).lower].
334-
335-
Note how the "convex" condition plays here: (2) and (3) together ensures
336-
[(f v).lower <= a <= (f v).upper]. Note that [v \in B], therefore
337-
[f v \in A]. By convexity, we have [a \in A], and thus we can safely
338-
apply [f'] to [a].
339-
*)
340314
let mlower = mlower obj mv in
341315
let mupper = mupper obj mv in
342316
if C.le obj a mlower
343317
then Ok ()
344318
else if not (C.le obj a mupper)
345319
then Error mupper
346320
else
347-
let a = C.join obj a mlower in
321+
(* At this point we know [a <= f v], therefore [a] is in the downward
322+
closure of [f]'s image. Therefore, asking [a <= f v] is equivalent to
323+
asking [f' a <= v]. *)
348324
let f' = C.left_adjoint obj f in
349325
let src = C.src obj f in
350326
let a' = C.apply src f' a in
@@ -395,7 +371,6 @@ module Solver_mono (C : Lattices_mono) = struct
395371
else if not (C.le obj mlower a)
396372
then Error mlower
397373
else
398-
let a = C.meet obj a mupper in
399374
let f' = C.right_adjoint obj f in
400375
let src = C.src obj f in
401376
let a' = C.apply src f' a in
@@ -464,6 +439,9 @@ module Solver_mono (C : Lattices_mono) = struct
464439
match submode_cmv ~log dst (mlower dst mv) mu with
465440
| Error a -> Error (mlower dst mv, a)
466441
| Ok () ->
442+
(* At this point, we know that [f v <= g u.upper], which means [f v]
443+
lies within the downward closure of [g]'s image. Therefore, asking [f
444+
v <= g u] is equivalent to asking [g' f v <= u] *)
467445
let g' = C.left_adjoint dst g in
468446
let src = C.src dst g in
469447
let g'f = C.compose src g' (C.disallow_right f) in

ocaml/typing/solver_intf.mli

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -120,32 +120,35 @@ module type Lattices_mono = sig
120120

121121
(* Usual notion of adjunction:
122122
Given two morphisms [f : A -> B] and [g : B -> A], we require [f a <= b]
123-
iff [a <= g b].
124-
125-
Our solver accepts a wider notion of adjunction and only requires the same
126-
condition on convex sublattices. To be specific, if [f] and [g] form a
127-
usual adjunction between [A] and [B], and [A] is a convex sublattice of
128-
[A'], and [B] is a convex sublattice of [B'], we say that [f] and [g]
129-
form a partial adjunction between [A'] and [B']. We do not require [f] to
130-
be defined on [A'\A]. Similar for [g].
131-
132-
Definition of convex sublattice can be found at:
133-
https://en.wikipedia.org/wiki/Lattice_(order)#Sublattices
134-
135-
For example: Define [A = B = {0, 1, 2}] with total ordering. Define both
136-
[f] and [g] to be the identity function. Obviously [f] and [g] form a usual
137-
adjunction. Now, further define [A'] = [A], and [B'] = [{0, 1, 2, 3}] with
138-
total ordering. Obviously [A] is a convex sublattice of [A'], and [B] of
139-
[B']. Then we say [f] and [g] forms a partial adjunction between [A'] and
140-
[B'].
141-
142-
The feature allows the user to invoke [f a <= b'], where [a \in A] and [b'
143-
\in B']. Similarly, they can invoke [a' <= g b], where [a' \in A'] and [b
144-
\in B].
145-
146-
Moreover, if [a' \in A'\A], it is still fine to apply [f] to [a'], but the
147-
result should not be used as a left mode. This is unfortunately not
148-
enforcable by the ocaml type system, and we have to rely on user's caution.
123+
iff [a <= g b] for all [a \in A] and [b \in B].
124+
125+
Our solver accepts a wider notion of adjunction:
126+
Given two morphisms [f : A -> B] and [g : B -> A], we require [f a <= b]
127+
iff [a <= g b] for any [a] in the downward closure of [g]'s image.
128+
129+
We say [f] is a partial left adjoint of [g], because [f] is only
130+
constrained on the downward closure of the image of [g]. As a result, [f]
131+
is not unique, since its valuation out of the required range is not
132+
constrained.
133+
134+
Dually, we can define the concept of partial right adjoint. Since partial
135+
adjoints are not unique, they don't form a pair: i.e., if a partial left
136+
joint of a partial right adjoint of [f] is not [f].
137+
138+
Concretely, the solver provides/requires the following guarantees
139+
(continuing the example above):
140+
141+
For the user of the [Solvers_polarized].
142+
- [g] applied to a right mode [m] can be used as a right mode without
143+
any restriction.
144+
- [f] applied to to a left mode [m] can be used as a left mode, given that
145+
the [m] is fully within the downward closure of [g]. This is unfortunately
146+
not enforcable by the ocaml type system, and we have to rely on user's
147+
caution.
148+
149+
For the supplier of the [Lattices_mono]:
150+
- The result of [left_adjoint g] is applied only on the downward closure of
151+
[g]'s image.
149152
*)
150153

151154
(* Note that [left_adjoint] and [right_adjoint] returns a [morph] weaker than

0 commit comments

Comments
 (0)