This page began as a snapshot of this complex boundary code and its exposition. We interpolate new function into the OCaml code to build the structure necessary for logical navigation within the body of the complex. This project would add undue hair to the original boundary code which I leave intact. Here are some early thoughts on the job of this modified program. This is the compact form of the program that gets updated as bugs are found.

This OCaml code computes the boundary and other artifacts of an oriented simplical complex.
Such a complex partitions some space (manifold) into simplexes called **zones** here.
Some finite set of points, which includes all the vertices of all the zones, is enumerated and this numbering is used to specify the vertices of each constituent zone.
Generally a list of integers, int list here, depicts some simplex by enumerating its vertices.
We seek a minimal addition of this code to support morphogenesis.
This code naturally discovers zones that share a facet and can thus make proper introductions which allow zones to send messages to their neighboring zones.

After morphogenesis finishes each zone holds for each neighbor a value of type `('a nAcc) = {ray : 'a rayp; curl : curlp}` which are functions to be called to send a message.
The type parameter `'a` names the type the value returned from some calls.
It is filled in by subsequent modules that care about the details of this type.

`morphgen` stands in the position of `boundary` in the simpler version.
Routine `morphgen` has two new parameters `nz` which it calls once for each zone, and `tl` which is a parameter that allows for peering into the complex and intervening therin.
This call creates the closure that becomes the essence of the zone throughout the subsequent ray tracing.
This code is a toy demonstration of the morphogenesis pattern.
`nz` takes the list of global vertex numbers for the new zone and returns a pair of functions called intNb and iZC here.
They are like ‘methods on the zone’.
intNb is called during morphogenesis once per neighbor.
It takes a local neighbor index and a channel for messages to the neighbor.
iZC is a function that receives such messages from neighbors.
There are two arguments in invocations to this function: the local index of the sender, and the message.
Whenever a facet is discovered to be shared by two zones, each zone intNb is called passing the local facet number, and the neighbor’s iZC, curried to identify that sender by neighbor index by which the recipient knows the sender.
At the end `morphgen` returns the boundary as a list.
Each facet at the boundary is accompanied with the function pair for the zone at the boundary.
In the transformation of the boundary code to scaffold code, some values that were vertex lists denoting facets, are changed to denote a pair (Chook, list) where the list is what went before, Chook is the hook as introduced above but Curried to know the zone number is which local number that the zone knows the facet by.
A message delivered to a chook is thus augmented by the facet number by which the recipient learns to which facet the message pertains.

Calls per zone to `nz` involve global vertex numbers which are typically necessary to produce metric information.
Subsequent calls to the hook and Chook involve only local information.
This restriction is to minimize the amount of code that is in a position to violate action-at-a-distance principles.

We include in red the type inferred by OCaml for each of the program fragments that we have copied into this explanation. We include in blue a sample invocation of the previous program fragment, in the form of an equality that can be verified by the OCaml REPL.

We use a sort routine that is expanded and expounded here. Also use these routine to support the small test cases that follow the definitions below.

exception Repeated_Vertex exception Logic_error let pe vl = match let rec mpa l th = match l with [] -> [], [] | (a, b)::c -> if th >= b then raise Repeated_Vertex; match mpa c b with sl, l -> (b::sl, (ref false, a)::l) in mpa (sort (fun (_, b) (_, d) -> b < d) (let rec numr l n = match l with [] -> [] | a::b -> (n, a)::(numr b (n + 1)) in numr vl 0)) (-1) with svl, spl -> let ar = Array.of_list spl in let rec dp i p = if i < 0 then p else let next = dp (i-1) in match ar.(i) with a, n -> if !a then next (not p) else let rec lop v = match ar.(v) with w, x -> if !w then raise Logic_error; w := true; if v = i then () else lop x in lop n; next p in dp (Array.length ar - 1) false, svl pe : int list -> bool * int list pe [3; 6; 5; 8] = (true, [3; 5; 6; 8])

let sl nz l = let (intNba, iZCa) = nz l in let rec sli l = match l with [] -> [] | h::t -> t::List.map (fun q -> h::q) (sli t) and app sll k = match sll with [] -> [] | h::t -> (h, (intNba k, iZCa k))::(app t (k+1)) in app (sli l) 0;; sl : ('a list -> (int -> 'b) * (int -> 'c)) -> 'a list -> ('a list * ('b * 'c)) list

let rc (nz, zl) = List.fold_left (fun acc (o, vl) -> (* Do all facets of this zone with facet list fac. *) (* Yield a pair of face lists assorted by parity. *) match (List.fold_left (fun (od, (even, odd)) face -> (not od, if o then (odd, face::even) else (face::odd, even))) (false, acc) (sl nz vl)) with (o, (l, r)) -> if o then (r, l) else (l, r)) ([], []) (List.map pe zl) rc : (int list -> (int -> 'a) * (int -> 'b)) * int list list -> (int list * ('a * 'b)) list * (int list * ('a * 'b)) list

let cmp (c, _) (d, _) = compare c d;; cmp : 'a * 'b -> 'a * 'c -> intTo control sorts of pairs of zone hook and simplex.

let b1 q = match (rc q) with a, b -> let ob = List.sort cmp in (ob a, ob b);; b1 : (int list -> (int -> 'a) * (int -> 'b)) * int list list -> (int list * ('a * 'b)) list * (int list * ('a * 'b)) list

let rec elim q tl = match q with | a, [] -> a, [] | [], b -> [], b | (a::b as rev), (c::d as obv) -> let w = cmp a c in if w < 0 then match elim (b, obv) tl with p, q -> a::p, q else if w > 0 then match elim (rev, d) tl with p, q -> p, c::q else (match (a, c) with (vl, (intNba, iZCa)), (_, (intNbb, iZCb)) -> (try let (tapl, tapr) = List.assoc vl tl in intNba (tapl iZCb); intNbb (tapr iZCa); with Not_found -> intNba iZCb; intNbb iZCa); elim (b, d) tl) elim : ('a * (('b -> 'c) * 'd)) list * ('a * (('d -> 'e) * 'b)) list -> ('a * (('b -> 'b) * ('d -> 'd))) list -> ('a * (('b -> 'c) * 'd)) list * ('a * (('d -> 'e) * 'b)) list

let morphgen nz x tl = match (elim (b1 (nz, x)) tl) with (p, q) -> List.append (List.map (fun (x, y) -> x, (false, y)) p) (List.map (fun (x, y) -> x, (true, y)) q) morphgen : (int list -> (int -> 'a -> 'b) * (int -> 'a)) -> int list list -> (int list * 'a tap2) list -> (int list * (bool * (('a -> 'b) * 'a))) list

Grok this. This too, too.