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