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