1 /*
  2  * Copyright (c) 2025-2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package hat.test;
 26 
 27 import hat.Accelerator;
 28 import hat.ComputeContext;
 29 import hat.KernelContext;
 30 import hat.NDRange;
 31 import hat.backend.Backend;
 32 import hat.types.BF16;
 33 import hat.buffer.BF16Array;
 34 import hat.device.DeviceSchema;
 35 import hat.device.NonMappableIface;
 36 import hat.test.annotation.HatTest;
 37 import hat.test.exceptions.HATAssertionError;
 38 import hat.test.exceptions.HATAsserts;
 39 import hat.test.exceptions.HATExpectedPrecisionError;
 40 import jdk.incubator.code.Reflect;
 41 import optkl.ifacemapper.MappableIface.*;
 42 
 43 import java.lang.invoke.MethodHandles;
 44 import java.util.Random;
 45 
 46 public class TestBFloat16Type {
 47 
 48     @Reflect
 49     public static void kernel_copy(KernelContext kernelContext, BF16Array a, BF16Array b) {
 50         if (kernelContext.gix < kernelContext.gsx) {
 51             BF16 ha = a.array(kernelContext.gix);
 52             b.array(kernelContext.gix).value(ha.value());
 53         }
 54     }
 55 
 56     @Reflect
 57     public static void bf16_02(KernelContext kernelContext, BF16Array a, BF16Array b, BF16Array c) {
 58         if (kernelContext.gix < kernelContext.gsx) {
 59             BF16 ha = a.array(kernelContext.gix);
 60             BF16 hb = b.array(kernelContext.gix);
 61             BF16 result = BF16.add(ha, hb);
 62             BF16 hc = c.array(kernelContext.gix);
 63             hc.value(result.value());
 64         }
 65     }
 66 
 67     @Reflect
 68     public static void bf16_03(KernelContext kernelContext, BF16Array a, BF16Array b, BF16Array c) {
 69         if (kernelContext.gix < kernelContext.gsx) {
 70             BF16 ha = a.array(kernelContext.gix);
 71             BF16 hb = b.array(kernelContext.gix);
 72 
 73             BF16 result = BF16.add(ha, BF16.add(hb, hb));
 74             BF16 hC = c.array(kernelContext.gix);
 75             hC.value(result.value());
 76         }
 77     }
 78 
 79     @Reflect
 80     public static void bf16_04(KernelContext kernelContext, BF16Array a, BF16Array b, BF16Array c) {
 81         if (kernelContext.gix < kernelContext.gsx) {
 82             BF16 ha = a.array(kernelContext.gix);
 83             BF16 hb = b.array(kernelContext.gix);
 84 
 85             BF16 r1 = BF16.mul(ha, hb);
 86             BF16 r2 = BF16.div(ha, hb);
 87             BF16 r3 = BF16.sub(ha, hb);
 88             BF16 r4 = BF16.add(r1, r2);
 89             BF16 r5 = BF16.add(r4, r3);
 90             BF16 hC = c.array(kernelContext.gix);
 91             hC.value(r5.value());
 92         }
 93     }
 94 
 95     @Reflect
 96     public static void bf16_05(KernelContext kernelContext, BF16Array a) {
 97         if (kernelContext.gix < kernelContext.gsx) {
 98             BF16 ha = a.array(kernelContext.gix);
 99             BF16 initVal = BF16.of( 2.1f);
100             ha.value(initVal.value());
101         }
102     }
103 
104     @Reflect
105     public static void bf16_06(KernelContext kernelContext, BF16Array a) {
106         if (kernelContext.gix < kernelContext.gsx) {
107             BF16 initVal = BF16.of(kernelContext.gix);
108             BF16 ha = a.array(kernelContext.gix);
109             ha.value(initVal.value());
110         }
111     }
112 
113     @Reflect
114     public static void bf16_08(KernelContext kernelContext, BF16Array a) {
115         if (kernelContext.gix < kernelContext.gsx) {
116             BF16 initVal = BF16.float2bfloat16(kernelContext.gix);
117             BF16 ha = a.array(kernelContext.gix);
118             ha.value(initVal.value());
119         }
120     }
121 
122     @Reflect
123     public static void bf16_09(KernelContext kernelContext, BF16Array a, BF16Array b) {
124         if (kernelContext.gix < kernelContext.gsx) {
125             BF16 ha = a.array(kernelContext.gix);
126             float f = BF16.bfloat162float(ha);
127             BF16 result = BF16.float2bfloat16(f);
128             BF16 hb = b.array(kernelContext.gix);
129             hb.value(result.value());
130         }
131     }
132 
133     @Reflect
134     public static void bf16_10(KernelContext kernelContext, BF16Array a) {
135         if (kernelContext.gix < kernelContext.gsx) {
136             BF16 ha = a.array(kernelContext.gix);
137             BF16 f16 = BF16.of(1.1f);
138             float f = BF16.bfloat162float(f16);
139             BF16 result = BF16.float2bfloat16(f);
140             ha.value(result.value());
141         }
142     }
143 
144     public interface LocalArray extends NonMappableIface {
145         BF16 array(int index);
146         DeviceSchema<LocalArray> deviceSchema = DeviceSchema.of(LocalArray.class,
147                 builder -> builder.array("array", 1024, bfloat16 -> bfloat16.field("value")));
148 
149         static LocalArray  create(Accelerator accelerator) {
150             return null;
151         }
152 
153         static LocalArray createLocal() {
154             return null;
155         }
156     }
157 
158     @Reflect
159     public static void bf16_11(KernelContext kernelContext, BF16Array a, BF16Array b) {
160         LocalArray sm = LocalArray.createLocal();
161         if (kernelContext.gix < kernelContext.gsx) {
162             int lix = kernelContext.lix;
163             BF16 ha = a.array(kernelContext.gix);
164 
165             sm.array(lix).value(ha.value());
166             kernelContext.barrier();
167 
168             BF16 hb = sm.array(lix);
169             b.array(kernelContext.gix).value(hb.value());
170         }
171     }
172 
173     @Reflect
174     public static void bf16_12(KernelContext kernelContext, BF16Array a, BF16Array b, BF16Array c) {
175         // Test the fluent API style
176         if (kernelContext.gix < kernelContext.gsx) {
177             BF16 ha = a.array(kernelContext.gix);
178             BF16 hb = b.array(kernelContext.gix);
179             BF16 result = BF16.add(ha,hb);
180             c.array(kernelContext.gix).value(result.value());
181         }
182     }
183 
184     @Reflect
185     public static void bf16_13(KernelContext kernelContext, BF16Array a, BF16Array b,  BF16Array c) {
186         // Test the fluent API style
187         if (kernelContext.gix < kernelContext.gsx) {
188             BF16 ha = a.array(kernelContext.gix);
189             BF16 hb = b.array(kernelContext.gix);
190             BF16 result = BF16.div(BF16.mul(BF16.sub(BF16.add(ha,hb),hb),ha),ha);
191             c.array(kernelContext.gix).value(result.value());
192         }
193     }
194 
195     @Reflect
196     public static void bf16_14(KernelContext kernelContext, BF16Array a, BF16Array b) {
197         // Testing mixed float types
198         if (kernelContext.gix < kernelContext.gsx) {
199             BF16 ha = a.array(kernelContext.gix);
200             float myFloat = 32.1f;
201             BF16 result = BF16.add(myFloat, ha);
202             b.array(kernelContext.gix).value(result.value());
203         }
204     }
205 
206     public interface PrivateArray extends NonMappableIface {
207         BF16 array(int index);
208         DeviceSchema<PrivateArray> deviceSchema = DeviceSchema.of(PrivateArray.class,
209                 builder -> builder.array("array", 256, bfloat16 -> bfloat16.field("value")));
210 
211         static PrivateArray  create(Accelerator accelerator) {
212             return null;
213         }
214 
215         static PrivateArray createPrivate() {
216             return null;
217         }
218     }
219 
220     @Reflect
221     public static void bf16_15(KernelContext kernelContext, BF16Array a, BF16Array b) {
222         PrivateArray privateArray = PrivateArray.createPrivate();
223         if (kernelContext.gix < kernelContext.gsx) {
224             int lix = kernelContext.lix;
225             BF16 ha = a.array(kernelContext.gix);
226             privateArray.array(lix).value(ha.value());
227             BF16 hb = privateArray.array(lix);
228             b.array(kernelContext.gix).value(hb.value());
229         }
230     }
231 
232     @Reflect
233     public static void bf16_16(KernelContext kernelContext, BF16Array a) {
234         BF16 ha = a.array(0);
235         BF16 hre = BF16.add(ha, ha);
236         hre = BF16.add(hre, hre);
237         a.array(0).value(hre.value());
238     }
239 
240     @Reflect
241     public static void bf16_17(KernelContext kernelContext, BF16Array a) {
242 
243         BF16 ha = a.array(0);
244         PrivateArray privateArray = PrivateArray.createPrivate();
245         privateArray.array(0).value(ha.value());
246 
247         // Obtain the value from private memory
248         BF16 acc = privateArray.array(0);
249 
250         // compute
251         acc = BF16.add(acc, acc);
252 
253         // store the result
254         a.array(0).value(acc.value());
255     }
256 
257     @Reflect
258     public static void compute01(@RO ComputeContext computeContext, @RO BF16Array a, @WO BF16Array b) {
259         computeContext.dispatchKernel(NDRange.of1D(a.length()), kernelContext -> TestBFloat16Type.kernel_copy(kernelContext, a, b));
260     }
261 
262     @Reflect
263     public static void compute02(@RO ComputeContext computeContext, @RO BF16Array a, @RO BF16Array b, @WO BF16Array c) {
264         computeContext.dispatchKernel(NDRange.of1D(a.length()),
265                 kernelContext -> TestBFloat16Type.bf16_02(kernelContext, a, b, c));
266     }
267 
268     @Reflect
269     public static void compute03(@RO ComputeContext computeContext, @RO BF16Array a, @RO BF16Array b, @WO BF16Array c) {
270         computeContext.dispatchKernel(NDRange.of1D(a.length()),
271                 kernelContext -> TestBFloat16Type.bf16_03(kernelContext, a, b, c));
272     }
273 
274     @Reflect
275     public static void compute04(@RO ComputeContext computeContext, @RO BF16Array a, @RO BF16Array b, @WO BF16Array c) {
276         computeContext.dispatchKernel(NDRange.of1D(a.length()),
277                 kernelContext -> TestBFloat16Type.bf16_04(kernelContext, a, b, c));
278     }
279 
280     @Reflect
281     public static void compute05(@RO ComputeContext computeContext, @WO BF16Array a) {
282         computeContext.dispatchKernel(NDRange.of1D(a.length()), kernelContext -> TestBFloat16Type.bf16_05(kernelContext, a));
283     }
284 
285     @Reflect
286     public static void compute06(@RO ComputeContext computeContext, @WO BF16Array a) {
287         computeContext.dispatchKernel(NDRange.of1D(a.length()), kernelContext -> TestBFloat16Type.bf16_06(kernelContext, a));
288     }
289 
290     @Reflect
291     public static void compute08(@RO ComputeContext computeContext, @WO BF16Array a) {
292         computeContext.dispatchKernel(NDRange.of1D(a.length()), kernelContext -> TestBFloat16Type.bf16_08(kernelContext, a));
293     }
294 
295     @Reflect
296     public static void compute09(@RO ComputeContext computeContext, @RW BF16Array a, @WO BF16Array b) {
297         computeContext.dispatchKernel(NDRange.of1D(a.length()), kernelContext -> TestBFloat16Type.bf16_09(kernelContext, a, b));
298     }
299 
300     @Reflect
301     public static void compute10(@RO ComputeContext computeContext, @WO BF16Array a) {
302         computeContext.dispatchKernel(NDRange.of1D(a.length()), kernelContext -> TestBFloat16Type.bf16_10(kernelContext, a));
303     }
304 
305     @Reflect
306     public static void compute11(@RO ComputeContext computeContext, @RO BF16Array a, @WO BF16Array b) {
307         computeContext.dispatchKernel(NDRange.of1D(a.length(),16), kernelContext -> TestBFloat16Type.bf16_11(kernelContext, a, b));
308     }
309 
310     @Reflect
311     public static void compute12(@RO ComputeContext computeContext, @RO BF16Array a, @RO BF16Array b, @WO BF16Array c) {
312         computeContext.dispatchKernel(NDRange.of1D(a.length()), kernelContext -> TestBFloat16Type.bf16_12(kernelContext, a, b, c));
313     }
314 
315     @Reflect
316     public static void compute13(@RO ComputeContext computeContext, @RO BF16Array a, @RO BF16Array b, @WO BF16Array c) {
317         computeContext.dispatchKernel(NDRange.of1D(a.length()), kernelContext -> TestBFloat16Type.bf16_13(kernelContext, a, b, c));
318     }
319 
320     @Reflect
321     public static void compute14(@RO ComputeContext computeContext, @RO BF16Array a, @WO BF16Array b) {
322         computeContext.dispatchKernel(NDRange.of1D(a.length()), kernelContext -> TestBFloat16Type.bf16_14(kernelContext, a, b));
323     }
324 
325     @Reflect
326     public static void compute15(@RO ComputeContext computeContext, @RO BF16Array a, @WO BF16Array b) {
327         computeContext.dispatchKernel(NDRange.of1D(a.length()), kernelContext -> TestBFloat16Type.bf16_15(kernelContext, a, b));
328     }
329 
330     @Reflect
331     public static void compute16(@RO ComputeContext computeContext, @RW BF16Array a) {
332         computeContext.dispatchKernel(NDRange.of1D(1), kernelContext -> TestBFloat16Type.bf16_16(kernelContext, a));
333     }
334 
335     @Reflect
336     public static void compute17(@RO ComputeContext computeContext, @RW BF16Array a) {
337         computeContext.dispatchKernel(NDRange.of1D(1), kernelContext -> TestBFloat16Type.bf16_17(kernelContext, a));
338     }
339 
340     @HatTest
341     @Reflect
342     public void test_bfloat16_01() {
343         final int size = 256;
344         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
345 
346         BF16Array arrayA = BF16Array.create(accelerator, size);
347         BF16Array arrayB = BF16Array.create(accelerator, size);
348         for (int i = 0; i < size; i++) {
349             arrayA.array(i).value(BF16.float2bfloat16(i).value());
350         }
351 
352         accelerator.compute(computeContext -> TestBFloat16Type.compute01(computeContext, arrayA, arrayB));
353 
354         for (int i = 0; i < size; i++) {
355             BF16 result = arrayB.array(i);
356             HATAsserts.assertEquals((float)i, BF16.bfloat162float(result), 0.001f);
357         }
358     }
359 
360     @HatTest
361     @Reflect
362     public void test_bfloat16_02() {
363         final int size = 256;
364         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
365 
366         BF16Array arrayA = BF16Array.create(accelerator, size);
367         BF16Array arrayB = BF16Array.create(accelerator, size);
368         BF16Array arrayC = BF16Array.create(accelerator, size);
369 
370         Random r = new Random(19);
371         for (int i = 0; i < size; i++) {
372             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
373             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
374         }
375 
376         accelerator.compute(computeContext -> TestBFloat16Type.compute02(computeContext, arrayA, arrayB, arrayC));
377 
378         for (int i = 0; i < size; i++) {
379             BF16 result = arrayC.array(i);
380             BF16 a = arrayA.array(i);
381             BF16 b = arrayB.array(i);
382             float res = BF16.bfloat162float(a) + BF16.bfloat162float(b);
383             HATAsserts.assertEquals(res, BF16.bfloat162float(result), 0.001f);
384         }
385     }
386     @HatTest
387     @Reflect
388     public void test_bfloat16_03() {
389         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
390 
391         final int size = 256;
392         BF16Array arrayA = BF16Array.create(accelerator, size);
393         BF16Array arrayB = BF16Array.create(accelerator, size);
394         BF16Array arrayC = BF16Array.create(accelerator, size);
395 
396         Random random = new Random();
397         for (int i = 0; i < arrayA.length(); i++) {
398             arrayA.array(i).value(BF16.float2bfloat16(random.nextFloat()).value());
399             arrayB.array(i).value(BF16.float2bfloat16(random.nextFloat()).value());
400         }
401 
402         accelerator.compute(computeContext -> TestBFloat16Type.compute03(computeContext, arrayA, arrayB, arrayC));
403 
404         for (int i = 0; i < arrayC.length(); i++) {
405             BF16 val = arrayC.array(i);
406             float fa = BF16.bfloat162float(arrayA.array(i));
407             float fb = BF16.bfloat162float(arrayB.array(i));
408             HATAsserts.assertEquals((fa + fb + fb), BF16.bfloat162float(val), 0.01f);
409         }
410     }
411 
412     @HatTest
413     @Reflect
414     public void test_bfloat16_04() {
415         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
416 
417         final int size = 256;
418         BF16Array arrayA = BF16Array.create(accelerator, size);
419         BF16Array arrayB = BF16Array.create(accelerator, size);
420         BF16Array arrayC = BF16Array.create(accelerator, size);
421 
422         Random random = new Random();
423         for (int i = 0; i < arrayA.length(); i++) {
424             arrayA.array(i).value(BF16.float2bfloat16(random.nextFloat()).value());
425             arrayB.array(i).value(BF16.float2bfloat16(random.nextFloat()).value());
426         }
427 
428         accelerator.compute(computeContext -> {
429             TestBFloat16Type.compute04(computeContext, arrayA, arrayB, arrayC);
430         });
431 
432         for (int i = 0; i < arrayC.length(); i++) {
433             BF16 gotResult = arrayC.array(i);
434 
435             // CPU Computation
436             BF16 ha = arrayA.array(i);
437             BF16 hb = arrayB.array(i);
438             BF16 r1 = BF16.mul(ha, hb);
439             BF16 r2 = BF16.div(ha, hb);
440             BF16 r3 = BF16.sub(ha, hb);
441             BF16 r4 = BF16.add(r1, r2);
442             BF16 r5 = BF16.add(r4, r3);
443 
444             HATAsserts.assertEquals(BF16.bfloat162float(r5), BF16.bfloat162float(gotResult), 0.01f);
445         }
446     }
447 
448     @HatTest
449     @Reflect
450     public void test_bfloat16_05() {
451         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
452 
453         final int size = 16;
454         BF16Array arrayA = BF16Array.create(accelerator, size);
455         for (int i = 0; i < arrayA.length(); i++) {
456             arrayA.array(i).value(BF16.float2bfloat16(0.0f).value());
457         }
458 
459         accelerator.compute(computeContext -> {
460             TestBFloat16Type.compute05(computeContext, arrayA);
461         });
462 
463         for (int i = 0; i < arrayA.length(); i++) {
464             BF16 val = arrayA.array(i);
465             HATAsserts.assertEquals(2.1f, BF16.bfloat162float(val), 0.01f);
466         }
467     }
468 
469     @HatTest
470     @Reflect
471     public void test_bfloat16_06() {
472         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
473 
474         final int size = 512;
475         BF16Array arrayA = BF16Array.create(accelerator, size);
476         for (int i = 0; i < arrayA.length(); i++) {
477             arrayA.array(i).value(BF16.float2bfloat16(0.0f).value());
478         }
479 
480         accelerator.compute(computeContext -> {
481             TestBFloat16Type.compute06(computeContext, arrayA);
482         });
483 
484         for (int i = 0; i < arrayA.length(); i++) {
485             BF16 val = arrayA.array(i);
486             try {
487                 HATAsserts.assertEquals(i, BF16.bfloat162float(val), 0.01f);
488             } catch (HATAssertionError hatAssertionError) {
489                 throw new HATExpectedPrecisionError(hatAssertionError.getMessage());
490             }
491 
492         }
493     }
494 
495     @HatTest
496     @Reflect
497     public void test_bfloat16_07() {
498         // Test CPU Implementation of BF16
499         BF16 a = BF16.of(2.5f);
500         BF16 b = BF16.of(3.5f);
501         BF16 c = BF16.add(a, b);
502         HATAsserts.assertEquals((2.5f + 3.5f), BF16.bfloat162float(c), 0.01f);
503 
504         BF16 d = BF16.sub(a, b);
505         HATAsserts.assertEquals((2.5f - 3.5f), BF16.bfloat162float(d), 0.01f);
506 
507         BF16 e = BF16.mul(a, b);
508         HATAsserts.assertEquals((2.5f * 3.5f), BF16.bfloat162float(e), 0.01f);
509 
510         BF16 f = BF16.div(a, b);
511         HATAsserts.assertEquals((2.5f / 3.5f), BF16.bfloat162float(f), 0.01f);
512     }
513 
514     @HatTest
515     @Reflect
516     public void test_bfloat16_08() {
517         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
518 
519         final int size = 256;
520         BF16Array arrayA = BF16Array.create(accelerator, size);
521         for (int i = 0; i < arrayA.length(); i++) {
522             arrayA.array(i).value(BF16.float2bfloat16(0.0f).value());
523         }
524 
525         accelerator.compute(computeContext -> {
526             TestBFloat16Type.compute08(computeContext, arrayA);
527         });
528 
529         for (int i = 0; i < arrayA.length(); i++) {
530             BF16 val = arrayA.array(i);
531             HATAsserts.assertEquals(i, BF16.bfloat162float(val), 0.01f);
532         }
533     }
534 
535     @HatTest
536     @Reflect
537     public void test_bfloat16_09() {
538         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
539 
540         final int size = 16;
541         BF16Array arrayA = BF16Array.create(accelerator, size);
542         BF16Array arrayB = BF16Array.create(accelerator, size);
543 
544         Random r = new Random(73);
545         for (int i = 0; i < arrayA.length(); i++) {
546             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
547         }
548 
549         accelerator.compute(computeContext -> TestBFloat16Type.compute09(computeContext, arrayA, arrayB));
550 
551         for (int i = 0; i < arrayB.length(); i++) {
552             BF16 val = arrayB.array(i);
553             HATAsserts.assertEquals(BF16.bfloat162float(arrayA.array(i)), BF16.bfloat162float(val), 0.01f);
554         }
555     }
556 
557     @HatTest
558     @Reflect
559     public void test_bfloat16_10() {
560         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
561         final int size = 256;
562         BF16Array arrayA = BF16Array.create(accelerator, size);
563 
564         accelerator.compute(computeContext -> TestBFloat16Type.compute10(computeContext, arrayA));
565 
566         for (int i = 0; i < arrayA.length(); i++) {
567             BF16 val = arrayA.array(i);
568             HATAsserts.assertEquals(1.1f, BF16.bfloat162float(val), 0.01f);
569         }
570     }
571 
572     @HatTest
573     @Reflect
574     public void test_bfloat16_11() {
575         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
576         final int size = 256;
577         BF16Array arrayA = BF16Array.create(accelerator, size);
578         BF16Array arrayB = BF16Array.create(accelerator, size);
579 
580         Random r = new Random(73);
581         for (int i = 0; i < arrayA.length(); i++) {
582             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
583         }
584 
585         accelerator.compute(computeContext -> TestBFloat16Type.compute11(computeContext, arrayA, arrayB));
586 
587         for (int i = 0; i < arrayB.length(); i++) {
588             BF16 val = arrayB.array(i);
589             HATAsserts.assertEquals(arrayA.array(i).value(), val.value());
590         }
591     }
592 
593     @HatTest
594     @Reflect
595     public void test_bfloat16_12() {
596         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
597         final int size = 1024;
598         BF16Array arrayA = BF16Array.create(accelerator, size);
599         BF16Array arrayB = BF16Array.create(accelerator, size);
600         BF16Array arrayC = BF16Array.create(accelerator, size);
601 
602         Random r = new Random(73);
603         for (int i = 0; i < arrayA.length(); i++) {
604             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
605             arrayB.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
606         }
607 
608         accelerator.compute(computeContext -> TestBFloat16Type.compute12(computeContext, arrayA, arrayB, arrayC));
609 
610         for (int i = 0; i < arrayB.length(); i++) {
611             BF16 result = arrayC.array(i);
612             HATAsserts.assertEquals(BF16.bfloat162float(BF16.add(arrayA.array(i), arrayB.array(i))), BF16.bfloat162float(result), 0.01f);
613         }
614     }
615 
616     @HatTest
617     @Reflect
618     public void test_bfloat16_13() {
619         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
620         final int size = 1024;
621         BF16Array arrayA = BF16Array.create(accelerator, size);
622         BF16Array arrayB = BF16Array.create(accelerator, size);
623         BF16Array arrayC = BF16Array.create(accelerator, size);
624 
625         Random r = new Random(73);
626         for (int i = 0; i < arrayA.length(); i++) {
627             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
628             arrayB.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
629         }
630 
631         accelerator.compute(computeContext -> TestBFloat16Type.compute13(computeContext, arrayA, arrayB, arrayC));
632 
633         for (int i = 0; i < arrayB.length(); i++) {
634             BF16 result = arrayC.array(i);
635             HATAsserts.assertEquals(BF16.bfloat162float(arrayA.array(i)), BF16.bfloat162float(result), 0.01f);
636         }
637     }
638 
639     @HatTest
640     @Reflect
641     public void test_bfloat16_14() {
642         // Testing mixed types
643         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
644         final int size = 1024;
645         BF16Array arrayA = BF16Array.create(accelerator, size);
646         BF16Array arrayB = BF16Array.create(accelerator, size);
647 
648         Random r = new Random(73);
649         for (int i = 0; i < arrayA.length(); i++) {
650             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
651         }
652 
653         accelerator.compute(computeContext -> TestBFloat16Type.compute14(computeContext, arrayA, arrayB));
654 
655         for (int i = 0; i < arrayB.length(); i++) {
656             BF16 result = arrayB.array(i);
657             try {
658                 HATAsserts.assertEquals(BF16.bfloat162float(arrayA.array(i)) + 32.1f, BF16.bfloat162float(result), 0.1f);
659             } catch (HATAssertionError hatAssertionError) {
660                 throw new HATExpectedPrecisionError(hatAssertionError.getMessage());
661             }
662         }
663     }
664 
665     @HatTest
666     @Reflect
667     public void test_bfloat16_15() {
668         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
669         final int size = 256;
670         BF16Array arrayA = BF16Array.create(accelerator, size);
671         BF16Array arrayB = BF16Array.create(accelerator, size);
672 
673         Random r = new Random(73);
674         for (int i = 0; i < arrayA.length(); i++) {
675             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
676         }
677 
678         accelerator.compute(computeContext -> TestBFloat16Type.compute15(computeContext, arrayA, arrayB));
679 
680         for (int i = 0; i < arrayB.length(); i++) {
681             BF16 val = arrayB.array(i);
682             HATAsserts.assertEquals(arrayA.array(i).value(), val.value());
683         }
684     }
685 
686     // Check accumulators
687     @HatTest
688     @Reflect
689     public void test_bfloat16_16() {
690         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
691         final int size = 1;
692         BF16Array arrayA = BF16Array.create(accelerator, size);
693 
694         Random r = new Random(73);
695         arrayA.array(0).value(BF16.float2bfloat16(10).value());
696 
697         accelerator.compute(computeContext -> TestBFloat16Type.compute16(computeContext, arrayA));
698 
699         BF16 val = arrayA.array(0);
700         HATAsserts.assertEquals(40.0f, BF16.bfloat162float(val), 0.01f);
701     }
702 
703     // Check accumulators in private memory
704     @HatTest
705     @Reflect
706     public void test_bfloat16_17() {
707         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
708         final int size = 1;
709         BF16Array arrayA = BF16Array.create(accelerator, size);
710 
711         Random r = new Random(73);
712         arrayA.array(0).value(BF16.float2bfloat16(10).value());
713 
714         accelerator.compute(computeContext -> TestBFloat16Type.compute17(computeContext, arrayA));
715 
716         BF16 val = arrayA.array(0);
717         HATAsserts.assertEquals(20.0f, BF16.bfloat162float(val), 0.01f);
718     }
719 
720 }