1 
  2 # More Complex Interface Mapping MavenStyleProject - The Cascade
  3 
  4 ----
  5 
  6 * [Contents](hat-00.md)
  7 * House Keeping
  8     * [Project Layout](hat-01-01-project-layout.md)
  9     * [Building Babylon](hat-01-02-building-babylon.md)
 10     * [Building HAT](hat-01-03-building-hat.md)
 11 * Programming Model
 12     * [Programming Model](hat-03-programming-model.md)
 13 * Interface Mapping
 14     * [Interface Mapping Overview](hat-04-01-interface-mapping.md)
 15     * [Cascade Interface Mapping](hat-04-02-cascade-interface-mapping.md)
 16 * Implementation Detail
 17     * [Walkthrough Of Accelerator.compute()](hat-accelerator-compute.md)
 18     * [How we minimize buffer transfers](hat-minimizing-buffer-transfers.md)
 19 
 20 ----
 21 
 22 # More Complex Interface Mapping MavenStyleProject - The Cascade
 23 
 24 Previously we showed probably the minimal useful mapping with S32Array
 25 
 26 The HaarCascade example has multiple nested interfaces representing data
 27 structures involving various nested structs and unions
 28 
 29 ```java
 30 public interface Cascade extends Buffer {
 31     int width();
 32     void width(int width);
 33     int height();
 34     void height(int height);
 35     interface Feature extends Buffer.StructChild {
 36         int id();
 37         float threshold();
 38         void id(int id);
 39         void threshold(float threshold);
 40         interface LinkOrValue extends Buffer.StructChild {
 41             interface Anon extends Buffer.UnionChild {
 42                 int featureId();
 43                 void featureId(int featureId);
 44                 float value();
 45                 void value(float value);
 46             }
 47             boolean hasValue();
 48             void hasValue(boolean hasValue);
 49             Anon anon();
 50         }
 51         LinkOrValue left();
 52         LinkOrValue right();
 53         interface Rect extends Buffer.StructChild {
 54             byte x();
 55             byte y();
 56             byte width();
 57             byte height();
 58             float weight();
 59             void x(byte x);
 60             void y(byte y);
 61             void width(byte width);
 62             void height(byte height);
 63             void weight(float height);
 64         }
 65         Rect rect(long idx);
 66     }
 67     int featureCount();
 68     void featureCount(int featureCount);
 69     Feature feature(long idx);
 70     interface Stage extends Buffer.StructChild {
 71         float threshold();
 72         short firstTreeId();
 73         short treeCount();
 74         int id();
 75         void id(int id);
 76         void threshold(float threshold);
 77         void firstTreeId(short firstTreeId);
 78         void treeCount(short treeCount);
 79     }
 80 
 81     int stageCount();
 82     void stageCount(int stageCount);
 83     Stage stage(long idx);
 84     interface Tree extends Buffer.StructChild {
 85         void id(int id);
 86         void firstFeatureId(short firstFeatureId);
 87         void featureCount(short featureCount);
 88         int id();
 89         short firstFeatureId();
 90         short featureCount();
 91     }
 92     int treeCount();
 93     void treeCount(int treeCount);
 94     Tree tree(long idx);
 95     Schema<Cascade> schema = Schema.of(Cascade.class, cascade -> cascade
 96             .fields("width", "height")
 97             .arrayLen("featureCount")
 98                 .array("feature", feature -> feature
 99                     .field("id")
100                     .field("threshold")
101                     .fields("left", "right", linkOrValue -> linkOrValue
102                             .field("hasValue")
103                             .pad(3)
104                             .field("anon", anon -> anon
105                                .field("featureId")
106                                .field("value")
107                             )
108                     )
109                     .array("rect", 3, rect -> rect
110                        .field("x")
111                        .field("y")
112                        .field("width")
113                        .field("height").
114                        .field("weight"))
115             )
116             .arrayLen("treeCount")
117                 .array("tree", tree -> tree
118                    .field("id")
119                    .field("featureCount")
120                    .field("firstFeatureId")
121                 )
122             .arrayLen("stageCount")
123                 .array("stage", stage -> stage
124                    .field("id")
125                    .field("threshold")
126                    .field("treeCount")
127                    .field("firstTreeId"))
128     );
129 }
130 ```
131 
132 Another great advantage of using interfaces is that we can choose
133 to re implement the interface in any was we see fit.
134 
135 For example we load  HaarCascades from XML files.
136 We therefore can create an implementation of the Cascade interface which just
137 loads the XML DOM... stores them in arrays and the interface methods just delegate to
138 the appropriately wrapped  w3c.Node tree nodes ;)
139 
140 If we know we are using Java backend we can actually
141 just pass the XMLCascade implementation directly to the backend...
142 
143 Actually the Cascade `create` method takes an existing
144 implementation of a Cascade and clones it.
145 So we can just pass it an XMLHaarCascade ;)
146 
147 So we build an XMLCascade then pass it to the `create` method of the iface
148 mapped Cascade
149 
150 ```java
151    XMLHaarCascadeModel haarCascade = XMLHaarCascadeModel.load(
152         ViolaJonesRaw.class.getResourceAsStream("haarcascade_frontalface_default.xml"));
153 
154    assert haarCascade instanceof Cascade; // Here it is just an interface
155 
156    Cascade cascade = Cascade.create(accelerator, haarCascade);
157 
158    // Now it can be used on the GPU
159 ```
160 
161 The implementation is currently hand crafted, but this could easily be automated.
162 
163 ```java
164  import java.lang.invoke.MethodHandles;
165 
166 static Cascade create(MethodHandles.Lookup lookup,BufferAllocator bufferAllocator, XMLHaarCascadeModel haarCascade) {
167 
168   Cascade cascade = bufferAllocator.allocate(SegmentMapper.of(lookup, Cascade.class,
169           JAVA_INT.withName("width"),
170           JAVA_INT.withName("height"),
171           JAVA_INT.withName("featureCount"),
172           sequenceLayout(haarCascade.features.size(), Feature.layout.withName(Feature.class.getSimpleName())).withName("feature"),
173           JAVA_INT.withName("stageCount"),
174           sequenceLayout(haarCascade.stages.size(), Stage.layout.withName(Stage.class.getSimpleName())).withName("stage"),
175           JAVA_INT.withName("treeCount"),
176           sequenceLayout(haarCascade.trees.size(), Tree.layout.withName(Tree.class.getSimpleName())).withName("tree")
177   ));
178   cascade.width(haarCascade.width());
179   cascade.height(haarCascade.height());
180   cascade.featureCount(haarCascade.features.size());
181   cascade.stageCount(haarCascade.stages.size());
182   cascade.treeCount(haarCascade.trees.size());
183   for (int idx = 0; idx < haarCascade.features.size(); idx++) {
184     Cascade.Feature cascadeFeature = cascade.feature(idx);
185     var haarfeature = haarCascade.features.get(idx);
186     cascadeFeature.id(haarfeature.id());
187     cascadeFeature.threshold(haarfeature.threshold());
188     Cascade.Feature.LinkOrValue cascadeLeft = cascadeFeature.left();
189     cascadeLeft.hasValue(haarfeature.left.hasValue());
190     if (haarfeature.left.hasValue()) {
191       cascadeLeft.anon().value(haarfeature.left.value());
192     } else {
193       cascadeLeft.anon().value(haarfeature.left.featureId());
194     }
195     Cascade.Feature.LinkOrValue cascadeRight = cascadeFeature.right();
196     cascadeRight.hasValue(haarfeature.right.hasValue());
197     if (haarfeature.right.hasValue()) {
198       cascadeRight.anon().value(haarfeature.right.value());
199     } else {
200       cascadeRight.anon().featureId(haarfeature.right.featureId());
201     }
202     for (int r = 0; r < 3; r++) {
203       var haarrect = haarfeature.rects[r];
204       if (haarrect != null) {
205         Cascade.Feature.Rect cascadeRect = cascadeFeature.rect(r);
206         cascadeRect.x(haarrect.x());
207         cascadeRect.y(haarrect.y());
208         cascadeRect.width(haarrect.width());
209         cascadeRect.height(haarrect.height());
210         cascadeRect.weight(haarrect.weight());
211       }
212     }
213   }
214   for (XMLHaarCascadeModel.Stage haarstage : haarCascade.stages) {
215     Cascade.Stage cascadeStage = cascade.stage(haarstage.id);
216     cascadeStage.id(haarstage.id());
217     cascadeStage.threshold(haarstage.threshold());
218     cascadeStage.firstTreeId(haarstage.firstTreeId());
219     cascadeStage.treeCount(haarstage.treeCount());
220   }
221 
222   for (XMLHaarCascadeModel.Tree haarTree : haarCascade.trees) {
223     Cascade.Tree cascadeTree = cascade.tree(haarTree.id());
224     cascadeTree.id(haarTree.id());
225     cascadeTree.firstFeatureId(haarTree.firstFeatureId());
226     cascadeTree.featureCount(haarTree.featureCount());
227   }
228   return cascade;
229 }
230 ```
231