@@ -6,49 +6,49 @@ Date: Dec 17, 2025
66
77## Introduction
88
9- Before reading this document is recommended to first review the [ closure glyph
10- segmentation] ( ./closure_glyph_segmentation.md ) document.
9+ Before reading this document is recommended to first review the
10+ [ closure glyph segmentation] ( ./closure_glyph_segmentation.md ) document. This document borrows concepts and terms from it .
1111
1212In closure glyph segmentation the closure analysis step is capable of locating glyph activation conditions that are
13- either fully disjunctive or fully conjunctive (eg. A or B or C). It is not capable of finding conditions that are a mix
14- of conjunction and disjunction (eg. (A and B) or (B and C)). These are referred to as complex conditions. By default
13+ either fully disjunctive or fully conjunctive (eg. ` ( A or B or C) ` ). It is not capable of finding conditions that are a mix
14+ of conjunction and disjunction (eg. ` (A and B) or (B and C) ` ). These are referred to as complex conditions. By default
1515glyphs with complex conditions are assigned to a patch that is always loaded, since the true conditions are not known.
1616
17- This document describes an algorithm which can be used to find the complete set of segments which are a part of the
18- complex condition for a glyph. If the set of segments which are present in a condition is known, then we can form a
19- purely disjunctive condition using those segments which is guaranteed to be a superset of the true condition. That is it
20- will always activate at least when the true condition would. This property allows the superset condition to be used for
21- a patch in place of the true condition without violating the closure requirement.
17+ This document describes an algorithm which can be used to find purely disjunctive conditions which are supersets of
18+ complex conditions. A superset condition is one that will activate at least whenever the true condition would. This
19+ property allows the superset condition to be used for a patch in place of the true condition without violating the
20+ closure requirement.
2221
23- For example if we had a glyph with a activation condition of ((A and B) or (B and C)) then this process will find the set
24- of segments {A, B, C} which would form the superset condition (A or B or C). In a segmentation we could then have a
25- patch with condition (A or B or C) which loads the glyph and this would satisfy the closure requirement. In the future
26- if we decide to develop an analysis to find the true condition then the segment set found by this process could be used
27- to narrow down the search space to only those segments involved in the condition.
22+ For a given complex condition there typically exists more than one possible superset disjunctive condition. The
23+ algorithm will find one of them, but not necessarily the smallest one. The found superset condition will always only
24+ contain only segments which appear in the original condition.
25+
26+ For example if we had a glyph with a activation condition of ` ((A and B) or (B and C)) ` then this process will find one
27+ of the possible superset conditions such as ` (A or C) ` , ` (A or B) ` , ` (B or C) ` , or ` (B) ` . In a segmentation we could
28+ then have a patch with the found condition which loads the glyph and this would satisfy the closure requirement.
2829
2930## Foundations
3031
3132The algorithm is based on the following assertions:
3233
33- 1 . For any complex activation condition of a glyph, a disjunction over all segments appearing in that condition
34- will always activate at least when the original condition does.
35-
36- 2 . Given some fully disjunctive condition, we can verify that condition is sufficient to meet the glyph closure
37- requirement for a glyph by the following procedure: compute a glyph closure of the union of all segments except for
38- those in the condition. If the glyph does not appear in this closure, then the condition satisfies the closure
39- requirement for that glyph. This is called the “additional conditions” check.
34+ 1 . Given some fully disjunctive condition for a glyph, we can verify that the condition is a superset of the true
35+ condition for the glyph and meets the closure requirement by the following procedure: compute a glyph closure of the
36+ union of all segments except for those in the condition. If the glyph does not appear in this closure, then the
37+ condition satisfies the closure requirement for that glyph and is a superset of the true condition. This is called
38+ the “additional conditions” check.
4039
41- 3 . The glyph closure of all segments will include the glyphs that we are analyzing.
40+ 2 . The glyph closure of all segments includes the glyph that we are analyzing.
4241
43- 4 . We have a glyph which has some true activation condition. If we compute a glyph closure of some combination of
42+ 3 . We have a glyph which has some true activation condition. If we compute a glyph closure of some combination of
4443 segments, then adding or removing a segment, which is not part of the activation condition, to the glyph closure input
4544 will have no affect on whether or not the glyph appears in the closure output.
4645
46+ 4 . The closure of no segments contains only glyphs from the initial font.
47+
4748## The Algorithm
4849
49- For each glyph with a complex condition we can use the above to find the complete set of segments which are part of the
50- glyph's complex condition. A condition which is a disjunction across these segments will satisfy the closure requirement
51- for that glyph.
50+ For a glyph with a complex condition we can use the above to find a superset disjunctive condition for that
51+ glyph's complex condition. These conditions will satisfy the closure requirement for each glyph.
5252
5353### Finding a Sub Condition
5454
@@ -63,10 +63,10 @@ Inputs:
6363Algorithm:
6464
65651 . Start with a set of all segments except those to be excluded, called ` to_test ` .
66- 2 . Initialize a second set of segments, ` required ` , to the empty set.
67- 3 . Remove a segment ` s ` from ` to_test ` and compute the glyph closure of ` to_test U required ` .
68- 4 . If ` glyph ` is not found in the closure then add ` s ` to ` required ` .
69- 5 . If ` to_test ` is empty, then return the sub condition ` required ` .
66+ 2 . Initialize a second set of segments, ` sub_condition ` , to the empty set.
67+ 3 . Remove a segment ` s ` from ` to_test ` and compute the glyph closure of ` to_test U sub_condition ` .
68+ 4 . If ` glyph ` is not found in the closure then add ` s ` to ` sub_condition ` .
69+ 5 . If ` to_test ` is empty, then return the sub condition ` sub_condition ` .
70706 . Otherwise, go back to step 3.
7171
7272### Finding the Complete Condition
@@ -83,32 +83,40 @@ Algorithm:
83832 . Execute the ` Finding a Sub Condition ` algorithm with ` condition ` as the excluded set.
84843 . Union the returned set into ` condition ` .
85854 . Compute the glyph closure of all segments except those in ` condition ` .
86- 5 . If ` glyph ` is found in the closure, then more conditions still exist. Go back to step 2.
86+ 5 . If ` glyph ` is found in the closure, then more sub conditions still exist. Go back to step 2.
87876 . Return the complete condition, ` condition ` .
8888
8989### Initial Font
9090
91- Any time a closure operation is executed by the above two algorithms it's necessary to union the subset definition
92- for the initial font into the closure input. That's because the closure of the initial font affects what's reachable
93- by the segments.
91+ Any time a closure operation is executed by the above two algorithms it's necessary to union the subset definition for
92+ the initial font into the closure input. This is required because the closure of the initial font affects what's
93+ reachable by the segments.
9494
9595### Why this works
9696
97+ Here we show this procedure is guaranteed to find a disjunctive superset of a glyph's true condition which includes
98+ only segments from the true condition, when the glyph is not already in the initial font:
99+
100+ * For each call to ` Finding a Sub Condition ` glyph will be in the closure of all non-excluded segments. For the first
101+ call this is guaranteed by assertion (2). For subsequent calls this is guaranteed by the "additional conditions" check
102+ which gates execution.
103+
97104* Any segments which are not part of the true condition will not impact the glyph's presence in the closure (assertion
98- (4)). As a result they will never be moved into the ` required ` set and will not be returned by `Finding a Sub
99- Condition` . Thus any segments returned by ` Finding a Sub Condition` are part of the true condition.
105+ (3)). Further by the previous point we know that at the start of ` Finding a Sub Condition ` the closure of all
106+ non-excluded segments will contain glyph. Thus testing a segment which is not part of the true condition will never
107+ result in glyph missing from the closure, and won't be added to ` sub_condition ` . Therefore ` Finding a Sub Condition `
108+ will only ever return segments that are part of the true condition.
100109
101- * Each iteration of ` Finding a Sub Condition ` is guaranteed to select at least one segment since we know that the
102- initial closure always starts with the glyph in it, and the closure of no segments will not have the glyph in it. So
103- at some point during the algorithm the glyph must be found to not be present. In the first iteration this is a result
104- of assertion (3). For subsequent iterations this is guaranteed by the "additional conditions" check prior to starting
105- the iteration.
110+ * ` Finding a Sub Condition ` will always return at least one segment: if when the last segment is tested ` sub_condition `
111+ is still the empty set, then the closure will be on no segments and will not have glyph in it. This is a result of
112+ assertion (4) and the premise that glyph is not already in the initial font. As a consequence the returned
113+ ` sub_condition ` will always have at least one segment in it.
106114
107115* Since all returned segments from ` Finding a Sub Condition ` are excluded from future calls, there will be a finite
108116 number of ` Finding a Sub Condition ` executions which return only segments part of the true condition.
109117
110118* Lastly, the algorithm terminates only once the additional conditions check finds no additional conditions,
111- guaranteeing we have found the complete superset disjunctive condition.
119+ guaranteeing we have found a superset disjunctive condition (assertion (1)) .
112120
113121## Making it More Performant
114122
0 commit comments