/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =============================================================================
 */

import * as tf from '@tensorflow/tfjs-core';
import {test_util} from '@tensorflow/tfjs-core';
// tslint:disable-next-line: no-imports-from-dist
import {ALL_ENVS, describeWithFlags} from '@tensorflow/tfjs-core/dist/jasmine_util';

import {MatMulProgramType} from './webgpu_util';

const {expectArraysClose} = test_util;
const MATMUL_SHARED_DIM_THRESHOLD = 1000;
function matmulTest(programType: MatMulProgramType) {
  return () => {
    let savedMatmulFlag = -1;
    beforeAll(() => {
      savedMatmulFlag = tf.env().get('WEBGPU_MATMUL_PROGRAM_TYPE') as number;
      tf.env().set('WEBGPU_MATMUL_PROGRAM_TYPE', programType);
    });
    afterAll(() => {
      tf.env().set('WEBGPU_MATMUL_PROGRAM_TYPE', savedMatmulFlag);
    });

    it('it works in delayed mode.', async () => {
      const savedFlag = tf.env().get('WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE');
      tf.env().set('WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE', 15);
      const a = tf.tensor2d([1, 2, 3, 4], [2, 2]);
      const b = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);

      const c = tf.matMul(a, b);

      const f = tf.tensor2d([0, 1, 0.5, 0, 0.25, 2], [2, 3]);
      const d = tf.mul(c, f);

      const dData = await d.data();
      test_util.expectArraysClose(
          dData, new Float32Array([0, 12, 7.5, 0, 6.5, 66]));
      tf.env().set('WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE', savedFlag);
    });

    it('it works in immediate mode.', async () => {
      const savedFlag = tf.env().get('WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE');
      tf.env().set('WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE', 1);
      const a = tf.tensor2d([1, 2, 3, 4], [2, 2]);
      const b = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);

      const c = tf.matMul(a, b);

      const f = tf.tensor2d([0, 1, 0.5, 0, 0.25, 2], [2, 3]);
      const d = tf.mul(c, f);

      const dData = await d.data();
      test_util.expectArraysClose(
          dData, new Float32Array([0, 12, 7.5, 0, 6.5, 66]));
      tf.env().set('WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE', savedFlag);
    });

    // tslint:disable-next-line:max-line-length
    it('matMul works when we do not check coords because tiles fit perfectly into input dimensions',
       async () => {
         const inputData = [
           0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,
           14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,
           28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,
           42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,
           56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,
           70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,
           84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,
           98,  99,  100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
           112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125,
           126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
           140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
           154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
           168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
           182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195,
           196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
           210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
           224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237,
           238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
           252, 253, 254, 255
         ];
         const a = tf.tensor2d(inputData, [16, 16]);
         const b = tf.tensor2d(inputData, [16, 16]);
         const expected = new Float32Array([
           19840,  19960,  20080,  20200,  20320,  20440,  20560,  20680,
           20800,  20920,  21040,  21160,  21280,  21400,  21520,  21640,
           50560,  50936,  51312,  51688,  52064,  52440,  52816,  53192,
           53568,  53944,  54320,  54696,  55072,  55448,  55824,  56200,
           81280,  81912,  82544,  83176,  83808,  84440,  85072,  85704,
           86336,  86968,  87600,  88232,  88864,  89496,  90128,  90760,
           112000, 112888, 113776, 114664, 115552, 116440, 117328, 118216,
           119104, 119992, 120880, 121768, 122656, 123544, 124432, 125320,
           142720, 143864, 145008, 146152, 147296, 148440, 149584, 150728,
           151872, 153016, 154160, 155304, 156448, 157592, 158736, 159880,
           173440, 174840, 176240, 177640, 179040, 180440, 181840, 183240,
           184640, 186040, 187440, 188840, 190240, 191640, 193040, 194440,
           204160, 205816, 207472, 209128, 210784, 212440, 214096, 215752,
           217408, 219064, 220720, 222376, 224032, 225688, 227344, 229000,
           234880, 236792, 238704, 240616, 242528, 244440, 246352, 248264,
           250176, 252088, 254000, 255912, 257824, 259736, 261648, 263560,
           265600, 267768, 269936, 272104, 274272, 276440, 278608, 280776,
           282944, 285112, 287280, 289448, 291616, 293784, 295952, 298120,
           296320, 298744, 301168, 303592, 306016, 308440, 310864, 313288,
           315712, 318136, 320560, 322984, 325408, 327832, 330256, 332680,
           327040, 329720, 332400, 335080, 337760, 340440, 343120, 345800,
           348480, 351160, 353840, 356520, 359200, 361880, 364560, 367240,
           357760, 360696, 363632, 366568, 369504, 372440, 375376, 378312,
           381248, 384184, 387120, 390056, 392992, 395928, 398864, 401800,
           388480, 391672, 394864, 398056, 401248, 404440, 407632, 410824,
           414016, 417208, 420400, 423592, 426784, 429976, 433168, 436360,
           419200, 422648, 426096, 429544, 432992, 436440, 439888, 443336,
           446784, 450232, 453680, 457128, 460576, 464024, 467472, 470920,
           449920, 453624, 457328, 461032, 464736, 468440, 472144, 475848,
           479552, 483256, 486960, 490664, 494368, 498072, 501776, 505480,
           480640, 484600, 488560, 492520, 496480, 500440, 504400, 508360,
           512320, 516280, 520240, 524200, 528160, 532120, 536080, 540040
         ]);

         const c = tf.matMul(a, b);
         const cData = await c.data();
         test_util.expectArraysClose(cData, expected);
       });

    // TODO: Make this test much smaller by controlling tile size with a flag.
    it('matMul A x B multiple tiles', async () => {
      const a = tf.tensor2d(
          [
            2, 7, 5, 1, 5, 1, 3, 2, 8, 8, 2, 0, 0, 0, 4, 0, 8, 4, 0, 5, 4, 1, 4,
            4, 2, 4, 3, 4, 4, 7, 4, 5, 0, 1, 4, 5, 5, 6, 6, 1, 9, 0, 0, 9, 0, 0,
            5, 3, 2, 2, 3, 4, 1, 1, 2, 4, 3, 4, 1, 6, 9, 2, 6, 5, 6, 5, 3, 6, 9,
            9, 7, 8, 8, 4, 8, 1, 4, 5, 1, 5, 8, 1, 9, 3, 7, 2, 2, 0, 5, 4, 3, 1,
            6, 1, 8, 4, 2, 9, 9, 6, 9, 0, 2, 3, 2, 3, 3, 9, 4, 8, 5, 6, 9, 0, 2,
            1, 5, 5, 8, 4, 9, 9, 2, 1, 5, 9, 6, 7, 9, 9, 3, 5, 3, 5, 7, 9, 8, 8,
            9, 0, 5, 8, 4, 5, 6, 1, 7, 8, 7, 2, 9, 9, 1, 1, 7, 9, 0, 4, 7, 7, 8,
            8, 2, 3, 8, 3, 3, 8, 7, 8, 3, 2, 5, 9, 1, 4, 4, 6, 4, 5, 8, 7, 9, 7,
            4, 4, 5, 6, 7, 1, 2, 0, 9, 9, 0, 3, 4, 7, 3, 6, 9, 3, 6, 0, 7, 0, 9,
            5, 4, 0, 2, 8, 4, 7, 6, 9, 6, 4, 2, 9, 8, 2, 5, 6, 2, 6, 2, 3, 3, 4,
            2, 5, 0, 3, 3, 2, 5, 4, 7, 3, 3, 8, 1, 4, 7, 8, 5, 3, 0, 0, 7, 7, 0,
            4, 1, 8, 3, 6, 9, 2, 6, 8, 8, 6, 1, 6, 0, 9, 2, 1, 4, 7, 4, 1, 5, 1,
            5, 4, 8, 0, 3, 3, 0, 6, 9, 3, 0, 6, 5, 3, 6, 4, 6, 1, 0, 2, 8, 1, 4,
            3, 9, 9, 3, 4, 1, 1, 1, 1, 9, 4, 0, 4, 1, 3, 3, 4, 3, 2, 3, 9, 6, 2,
            1, 3, 3, 8, 0, 9, 4, 0, 6, 8, 5, 7, 3, 1, 2, 3, 5, 4, 3, 9, 1, 6, 4,
            0, 6, 7, 8, 0, 2, 2, 0, 1, 8, 6, 6, 3, 6, 7, 2, 3, 2, 7, 9, 0, 1, 9,
            8, 7, 8, 4, 6, 4, 6, 5, 8, 8, 9, 5, 5, 1, 7, 3, 0, 2, 2, 3, 8, 1, 8,
            1, 2, 3, 6, 0, 1, 3, 0, 8, 9, 9, 6, 8, 8, 1, 5, 1, 7, 8, 8, 3, 3, 4,
            7, 3, 9, 3, 3, 7, 9, 8, 3, 8, 6, 8, 4, 2, 2, 5, 0, 4, 0, 7, 7, 0, 0,
            3, 1, 8, 3, 2, 0, 1, 6, 5, 3, 9, 6, 7, 5, 6, 5, 4, 2, 7, 0, 3, 2, 8,
            3, 5, 8, 3, 5, 1, 3, 8, 2, 1, 5, 3, 3, 3, 5, 8, 3, 2, 0, 7, 4, 9, 4,
            5, 0, 8, 7, 3, 2, 1, 8, 4, 5, 7, 0, 7, 0, 7, 4, 6, 1, 6, 1, 9, 7, 2,
            5, 6, 0, 6, 3, 5, 3, 9, 9, 5, 8, 2, 9, 2, 8, 6, 3, 1, 9, 7, 4, 7, 8,
            6, 3, 6, 1, 5, 5, 6, 0, 6, 6, 3, 1, 8, 9, 1, 2, 0, 3, 8, 4, 0, 0, 5,
            1, 0, 7, 2, 5, 3, 7, 7, 8, 1, 3, 4, 5, 8, 4, 7, 6, 4, 7, 6, 9, 9, 2,
            9, 1, 7, 3, 2, 3, 0, 1, 6, 8, 5, 9, 2, 4, 4, 9, 5, 0, 2, 2, 7, 5, 3,
            6, 2, 0, 8, 3, 8, 2, 0, 1, 5, 8, 5, 2, 8, 6, 0, 2, 3, 7, 0, 9, 2, 0,
            7, 0, 9, 4, 0, 2, 5, 4, 2, 7, 3, 2, 9, 1, 2, 6, 3, 3, 5, 3, 6, 5, 4,
            0, 8, 6, 9, 8, 5, 3, 1, 5, 1, 2, 3, 2, 9, 7, 3, 1, 0, 6, 5, 6, 2, 7,
            5, 1, 4, 9, 0, 9, 7, 1, 7, 5, 0, 5, 7, 7, 9, 0, 0, 7, 7, 6, 3, 3, 0,
            0, 8, 6, 4, 8, 2, 9, 2, 3, 4, 1, 4, 5, 3, 1, 6, 4, 5, 1, 7, 0, 5, 6,
            4, 1, 4, 4, 9, 1, 1, 6, 1, 2, 9, 4, 7, 7, 7, 7, 5, 5, 0, 5, 1, 0, 6,
            1, 6, 1, 7, 4, 0, 5, 3, 4, 4, 4, 7, 9, 1, 6, 8, 6, 4, 7, 7, 3, 6, 5,
            8, 0, 0, 1, 4, 6, 7, 4, 7, 5, 3, 3, 4, 5, 9, 8, 8, 6, 3, 2, 8, 7, 2,
            7, 5, 9, 9, 2, 6, 9, 4, 0, 5, 8, 0, 3, 0, 1, 3, 1, 7, 2, 1, 9, 2, 3,
            4, 5, 6, 5, 2, 7, 9, 4, 9, 8, 8, 0, 8, 3, 4, 6, 6, 6, 6, 7, 8, 8, 3,
            3, 3, 2, 0, 7, 6, 4, 9, 5, 1, 0, 1, 7, 9, 3, 4, 2, 9, 7, 0, 5, 5, 6,
            3, 1, 9, 2, 7, 2, 8, 5, 9, 7, 9, 1, 9, 4, 4, 4, 0, 1, 1, 1, 8, 5, 3,
            3, 4, 7, 9, 3, 3, 6, 4, 4, 5, 0, 5, 6, 4, 4, 5, 5, 9, 7, 8, 6, 0, 6,
            3, 4, 4, 9, 6, 7, 7, 7, 5, 3, 2, 3, 3, 7, 0, 5, 9, 5, 6, 7, 6, 0, 6,
            2, 7, 7, 0, 7, 6, 6, 7, 3, 6, 8, 9, 7, 8, 1, 7, 8, 9, 0, 0, 3, 8, 2,
            2, 9, 1, 0, 7, 7, 3, 4, 2, 4, 7, 0, 2, 4, 2, 3, 5, 8, 5, 4, 4, 2, 3,
            1, 7, 0, 4, 1, 8, 8, 2, 9, 7, 2, 1, 8, 1, 8, 6, 2, 8, 9, 9, 2, 4, 3,
            6, 1, 3, 7, 4, 1, 1, 3, 2, 0, 1, 6, 2, 1, 5, 0, 9, 9, 1, 8, 4, 8, 7,
            9, 5, 9, 8, 8, 1, 3, 4, 7, 5, 4, 9, 0, 9, 9, 3, 5, 1, 6, 6, 8, 9, 0,
            0, 0, 7, 5, 1, 3, 7, 9, 0, 4, 6, 3, 7, 7, 3, 8, 6, 4, 5, 7, 1, 0, 0,
            8, 0, 2, 1, 5, 4, 0, 3, 0, 0, 7, 2, 2, 3, 0, 9, 0, 4, 4, 8, 9, 1, 5,
            8, 3, 2, 1, 8, 9, 8, 1, 1, 0, 8, 3, 2, 3, 0, 6, 2, 2, 3, 9, 5, 7, 0,
            1, 0, 3, 5, 4, 4, 5, 5, 1, 0, 2, 6, 3, 4, 7, 0, 7, 7, 9, 0, 1, 4, 9,
            9, 2, 1, 7, 4, 2, 1, 1, 1, 0, 2, 7, 4, 1, 8, 1, 7, 8, 1, 1, 5, 3, 5,
            4, 2, 1, 0, 5, 9, 9, 6, 8, 4, 9, 9, 0, 5, 2, 9, 8, 1, 4, 0, 2, 9, 6,
            7, 2, 0, 4, 0, 1, 1, 9, 5, 9, 0, 4, 0, 7, 1, 3, 8, 0, 5, 3, 4, 9, 8,
            7, 8, 8, 5, 6, 8, 6, 6, 6, 1, 3, 4, 7, 6, 9, 6, 3, 1, 3, 8, 4, 4, 0,
            1, 9, 5, 9, 1, 6, 8, 6, 0, 1, 8, 1, 8, 9, 9, 0, 6, 0, 2, 6, 2, 6, 9,
            1, 0, 2, 7, 0, 9, 2, 3, 9, 0, 2, 9, 9, 5, 4, 1, 3, 5, 4, 2, 6, 5, 9,
            8, 0, 8, 3, 4, 7, 4, 4, 5, 6, 8, 4, 7, 4, 1, 9, 5, 6, 3, 8, 3, 4, 0,
            3, 6, 1, 1, 6, 8, 6, 6, 4, 8, 9, 8, 8, 9, 0, 1, 5, 9, 7, 9, 0, 6, 4,
            4, 5, 8, 4, 2, 8, 1, 3, 2, 1, 5, 6, 6, 6, 2, 9, 0, 8, 1, 8, 2, 6, 4,
            3, 0, 3, 8, 6, 5, 7, 6, 8, 1, 5, 6, 7, 7, 5, 6, 7, 0, 0, 8, 3, 6, 0,
            7, 2, 8, 8, 4, 7, 8, 7, 5, 6, 2, 7, 3, 0, 1, 0, 1, 9, 7, 7, 0, 1, 8,
            0, 2, 6, 2, 6, 4, 6, 0, 0, 8, 9, 7, 4, 1, 5, 6, 2, 5, 3, 8, 4, 0, 4,
            1, 5, 9, 8, 1, 8, 0, 0, 0, 0, 3, 8, 8, 9, 6, 1, 2, 3, 3, 9, 9, 6, 4,
            3, 1, 7, 2, 8, 4, 5, 6, 6, 3, 6, 7, 6, 5, 5, 7, 9, 7, 9, 9, 9, 8, 8,
            0, 7, 0, 6, 6, 9, 6, 3, 5, 2, 3, 2, 6, 8, 1, 6, 0, 8, 6, 8, 6, 0, 4,
            6, 8, 1, 7, 2, 5, 3, 2, 2, 5, 1, 5, 2, 6, 8, 5, 0, 5, 3, 9, 2, 4, 1,
            6, 5, 5, 7, 7, 8, 2, 1, 7, 5, 7, 2, 8, 0, 6, 7, 2, 7, 0, 6, 9, 9, 7,
            7, 5, 1, 4, 5, 3, 0, 3, 2, 0, 0, 0, 7, 7, 8, 9, 0, 0, 7, 8, 5, 2, 9,
            6, 2, 2, 1, 8, 3, 1, 1, 7, 7, 1, 0, 7, 3, 4, 0, 3, 7, 6, 2, 7, 2, 6,
            9, 4, 9, 5, 4, 6, 6, 6, 5, 6, 9, 6, 8, 6, 1, 3, 3, 2, 2, 7, 4, 6, 8,
            3, 3, 1, 3, 4, 8, 7, 6, 7, 6, 0, 7, 2, 0, 1, 6, 3, 3, 9, 2, 0, 3, 9,
            3, 9, 2, 8, 6, 2, 8, 0, 2, 2, 5, 6, 5, 7, 4, 2, 5, 6, 4, 8, 9, 0, 6,
            5, 2, 7, 3, 9, 0, 4, 2, 4, 5, 2, 8, 9, 1, 2, 3, 7, 2, 7, 2, 5, 0, 1,
            5, 0, 5, 1, 7, 4, 4, 5, 7, 0, 7, 2, 7, 1, 6, 5, 6, 2, 1, 6, 1, 3, 0,
            4, 6, 3, 9, 5, 1, 1, 3, 9, 5, 5, 8, 6, 9, 0, 4, 0, 6, 8, 7, 3, 6, 4,
            5, 6, 2, 4, 5, 1, 0, 7, 3, 3, 3, 5, 2, 0, 2, 7, 5, 6, 2, 0, 4, 8, 0,
            8, 6, 9, 5, 3, 0, 5, 0, 5, 3, 9, 5, 6, 8, 2, 9, 9, 6, 1, 5, 9, 5, 6,
            2, 8, 9, 3, 5, 4, 0, 1, 8, 2, 4, 4, 6, 4, 5, 8, 6, 0, 1, 3, 3, 6, 8,
            6, 1, 7, 1, 5, 5, 7, 2, 3, 2, 0, 2, 0, 7, 4, 6, 0, 0, 5, 6, 6, 0, 2,
            2, 0, 5, 3, 9, 9, 5, 1, 5, 9, 8, 4, 3, 4, 2, 1, 4, 7, 9, 5, 5, 9, 9,
            1, 8, 2, 8, 0, 7, 9, 8, 8, 8, 0, 8, 1, 3, 9, 2, 0, 9, 5, 5, 6, 2, 5,
            5, 6, 7, 0, 4, 9, 5, 3, 0, 6, 6, 2, 1, 6, 7, 4, 5, 3, 0, 9, 7, 8, 5,
            7, 9, 0, 8, 6, 9, 6, 7, 3, 2, 2, 1, 0, 6, 7, 3, 7, 7, 4, 6, 7, 6, 3,
            3, 9, 9, 4, 7, 9, 2, 6, 1, 5, 5, 9, 3, 5, 8, 3, 8, 5, 8, 5, 3, 2, 7,
            0, 6, 5, 5, 5, 9, 2, 1, 2, 4, 9, 8, 8, 7, 3, 7, 5, 6, 3, 6, 5, 9, 2,
            6, 4, 4, 7, 3, 0, 5, 3, 6, 6, 6, 9, 4, 3, 3, 0, 0, 3, 6, 7, 8, 6, 6,
            6, 8, 4, 9, 4, 2, 6, 5, 5, 1, 5, 5, 7, 0, 5, 5, 5, 0, 8, 9, 9, 0, 7,
            6, 5, 5, 8, 7, 8, 3, 1, 8, 4, 6, 6, 6, 1, 7, 0, 9, 5, 8, 7, 7, 4, 5,
            3, 1, 7, 4, 6, 6, 6, 5, 7, 5, 3, 1, 0, 2, 7, 8, 8, 4, 6, 3, 2, 3, 6,
            3, 2, 0, 0, 1, 4, 7, 4, 3, 7, 9, 0, 9, 3, 4, 3, 8, 6, 3, 5, 8, 1, 0,
            1, 6, 0, 1, 8, 9, 5, 8, 2, 7, 7, 1, 6, 7, 4, 1, 0, 3, 1, 6, 5, 5, 0,
            9, 4, 7, 1, 4, 3, 4, 2, 4, 5, 0, 6, 4, 8, 7, 0, 6, 5, 3, 9, 3, 1, 3,
            9, 3, 5, 1, 8, 2, 7, 1, 3, 8, 7, 3, 5, 6, 6, 2, 7, 7, 1, 3, 7, 1, 6,
            5, 6, 3, 1, 7, 0, 5, 2, 6, 7, 3, 2, 5, 9, 4, 8, 1, 8, 0, 0, 0, 8, 5,
            2, 0, 8, 3, 6, 6, 3, 7, 8, 0, 0, 7, 3, 9, 1, 6, 0, 0, 2, 4, 3, 3, 9,
            0, 8, 3, 3, 9, 5, 4, 5, 3, 8, 4, 7, 2, 2, 9, 9, 7, 6, 4, 4, 4, 5, 2,
            6, 3, 9, 5, 3, 5, 8, 2, 9, 9, 4, 4, 7, 3, 3, 9, 0, 3, 3, 3, 5, 5, 8,
            3, 9, 2, 0, 9, 3, 6, 8, 0, 2, 6, 0, 6, 6, 0, 5, 9, 6, 5, 7, 0, 4, 3,
            1, 9, 6, 4, 0, 6, 6, 7, 3, 7, 9, 7, 7, 3, 1, 4, 2, 9, 9, 5, 5, 3, 3,
            1, 8, 2, 0, 5, 7, 4, 9, 3, 3, 0, 5, 7, 0, 9, 0, 9, 9, 2, 4, 2, 3, 7,
            1, 3, 1, 2, 5, 0, 3, 8, 6, 3, 1, 5, 1, 1, 0, 1, 7, 9, 4, 8, 0, 1, 7,
            9, 3, 8, 3, 0, 5, 1, 1, 5, 5, 7, 6, 3, 6, 0, 4, 6, 5, 2, 2, 3, 6, 6,
            2, 7, 1, 9, 9, 1, 1, 8, 0, 1, 2, 1, 4, 4, 3, 9, 3, 6, 1, 4, 3, 3, 9,
            3, 4, 8, 1, 7, 8, 8, 8, 2, 3, 7, 4, 4, 2, 8, 1, 5, 6, 1, 1, 3, 0, 7,
            1, 8, 4, 7, 2, 6, 9, 1, 9, 0, 0, 5, 1, 7, 3, 4, 1, 9, 8, 7, 4, 0, 8,
            3, 6, 8, 5, 7, 6, 6, 0, 2, 8, 8, 2, 6, 6, 8, 3, 5, 9, 9, 9, 2, 4, 2,
            1, 1, 0, 1, 8, 4, 5, 6, 9, 5, 8, 3, 1, 1, 6, 7, 5, 3, 0, 6, 3, 0, 1,
            9, 9, 1, 7, 9, 4, 0, 3, 1, 9, 7, 3, 8, 5, 9, 6, 5, 6, 8, 6, 2, 4, 8,
            3, 5, 5, 3, 4, 0, 1, 4, 0, 0, 7, 4, 0, 4, 0, 8, 3, 4, 6, 1, 1, 9, 0,
            0, 7, 7, 0, 3, 0, 8, 5, 7, 3, 3, 4, 3, 1, 2, 2, 0, 5, 4, 2, 8, 0, 9,
            0, 2, 6, 1, 9, 3, 1, 9, 3, 5, 4, 1, 1, 3, 4, 5, 9, 8, 3, 6, 3, 2, 4,
            9, 0, 3, 5, 4, 9, 7, 0, 3, 9, 8, 9, 2, 9, 5, 8, 5, 6, 5, 2, 2, 5, 9,
            9, 2, 3, 5, 2, 2, 4, 0, 6, 7, 0, 8, 5, 9, 4, 9, 8, 2, 5, 0, 2, 1, 1,
            0, 0, 0, 3, 7, 0, 7, 9, 8, 1, 1, 4, 8, 6, 2, 6, 9, 7, 7, 9, 0, 4, 5,
            9, 8, 4, 3, 8, 1, 1, 1, 5, 9, 0, 1, 2, 2, 4, 9, 1, 4, 7, 8, 4, 7, 3,
            4, 5, 8, 6, 0, 9, 2, 6, 9, 5, 8, 8, 1, 3, 6, 2, 0, 8, 1, 0, 1, 8, 7,
            5, 7, 4, 0, 4, 8, 9, 7, 3, 5, 2, 4, 6, 8, 2, 0, 9, 7, 9, 5, 4, 8, 4,
            2, 2, 8, 7, 3, 0, 6, 6, 1, 4, 9, 7, 7, 1, 8, 2, 2, 0, 1, 8, 2, 5, 7,
            4, 7, 7, 1, 8, 5, 5, 6, 8, 2, 7, 5, 3, 1, 7, 9, 9, 1, 9, 6, 8, 7, 7,
            8, 1, 9, 5, 5, 5, 2, 4, 6, 2, 7, 7, 3, 2, 1, 4, 0, 7, 7, 4, 6, 9, 5,
            0, 7, 0, 0, 1, 3, 1, 7, 8, 7, 3, 2, 3, 9, 0, 5, 6, 9, 9, 1, 4, 2, 3,
            5, 0, 7, 5, 6, 5, 1, 6, 8, 7, 8, 3, 2, 3, 4, 2, 1, 9, 2, 8, 9, 9, 4,
            4, 8, 6, 3, 0, 4, 5, 7, 9, 2, 3, 8, 0, 8, 3, 3, 8, 1, 2, 2, 8, 1, 5,
            1, 3, 1, 3, 7, 8, 6, 3, 2, 8, 8, 3, 1, 0, 7, 2, 3, 1, 1, 5, 1, 7, 0,
            1, 1, 5, 9, 6, 8, 3, 7, 3, 9, 0, 3, 5, 4, 9, 0, 6, 9, 5, 9, 6, 4, 2,
            3, 7, 9, 3, 4, 0, 9, 2, 2, 1, 9, 9, 8, 2, 3, 2, 5, 6, 3, 7, 6, 3, 5,
            5, 7, 6, 3, 1, 6, 8, 3, 9, 1, 8, 2, 6, 5, 9, 1, 0, 1, 0, 3, 6, 4, 1,
            2, 1, 0, 4, 9, 8, 6, 3, 1, 2, 4, 2, 5, 9, 6, 6, 4, 3, 0, 1, 0, 6, 7,
            2, 7, 9, 5, 4, 0, 4, 6, 6, 5, 2, 4, 2, 4, 5, 1, 6, 0, 3, 2, 0, 0, 1,
            3, 0, 3, 7, 5, 8, 1, 3, 8, 3, 7, 0, 1, 1, 0, 4, 5, 6, 2, 6, 5, 6, 6,
            4, 8, 8, 8, 5, 2, 7, 1, 2, 2, 3, 2, 8, 3, 4, 3, 2, 3, 9, 7, 6, 3, 9,
            8, 1, 2, 6, 7, 0, 2, 1, 5, 1, 4, 3, 3, 4, 8, 6, 6, 5, 8, 0, 0, 8, 5,
            6, 3, 5, 4, 5, 6, 7, 6, 9, 5, 0, 0, 2, 1, 3, 0, 0, 0, 4, 0, 9, 1, 1,
            7, 0, 6, 0, 7, 3, 6, 7, 0, 9, 3, 2, 0, 0, 3, 9, 2, 0, 5, 2, 0, 1, 6,
            2, 8, 6, 8, 0, 8, 1, 2, 6, 4, 7, 0, 7, 3, 4, 8, 5, 1, 8, 8, 4, 0, 9,
            1, 5, 6, 0, 9, 2, 7, 6, 9, 5, 5, 6, 0, 4, 3, 9, 6, 5, 7, 7, 7, 7, 1,
            0, 1, 3, 8, 3, 6, 4, 6, 5, 9, 9, 8, 4, 6, 0, 7, 3, 0, 8, 5, 5, 2, 4,
            5, 8, 6, 3, 5, 8, 5, 4, 8, 0, 8, 3, 4, 5, 7, 2, 0, 1, 3, 2, 5, 4, 5,
            0, 3, 3, 2, 9, 9, 5, 8, 4, 7, 7, 6, 4, 9, 3, 5, 8, 0, 6, 8, 7, 0, 6,
            9, 1, 3, 4, 9, 5, 2, 7, 3, 4, 0, 0, 2, 0, 6, 0, 8, 4, 9, 3, 2, 4, 3,
            4, 9, 7, 6, 1, 5, 5, 0, 2, 7, 2, 4, 3, 9, 2, 6, 5, 9, 3, 9, 3, 6, 6,
            8, 8, 5, 7, 7, 3, 0, 8, 9, 9, 0, 8, 6, 2, 4, 6, 1, 1, 0, 0, 5, 6, 0,
            3, 5, 1, 0, 7, 6, 9, 3, 1, 0, 4, 4, 9, 2, 6, 4, 3, 2, 8, 5, 9, 0, 3,
            8, 0, 9, 6, 1, 8, 7, 3, 6, 3, 9, 8, 4, 5, 6, 7, 6, 5, 6, 0, 3, 8, 9,
            1, 9, 5, 0, 3, 3, 0, 5, 9, 2, 4, 2, 6, 3, 4, 7, 2, 1, 8, 1, 4, 9, 9,
            9, 2, 9, 6, 9, 9, 6, 4, 5, 4, 7, 3, 8, 3, 5, 5, 5, 3, 7, 4, 5, 0, 0,
            6, 5, 0, 3, 5, 4, 7, 3, 2, 1, 4, 3, 5, 6, 3, 3, 2, 9, 6, 0, 8, 5, 6,
            8, 3, 7, 6, 4, 2, 7, 1, 2, 4, 7, 2, 0, 4, 2, 7, 5, 7, 3, 0, 0, 4, 7,
            9, 0, 6, 3, 8, 5, 3, 8, 0, 2, 4, 0, 9, 6, 4, 4, 8, 0, 5, 9, 5, 8, 2,
            3, 8, 8, 5, 2, 2, 1, 3, 3, 2, 0, 6, 4, 6, 3, 4, 2, 0, 2, 6, 6, 6, 2,
            5, 0, 0, 5, 6, 0, 8, 7, 4, 2, 7, 4, 9, 8, 3, 2, 2, 7, 7, 5, 7, 3, 4,
            7, 4, 8, 0, 5, 2, 0, 1, 0, 2, 2, 5, 7, 5, 4, 1, 9, 4, 6, 9, 8, 3, 2,
            9, 4, 0, 7, 6, 8, 7, 1, 5, 1, 9, 1, 5, 1, 0, 4, 9, 5, 3, 6, 6, 4, 0,
            8, 1, 9, 6, 8, 3, 3, 0, 0, 7, 6, 5, 5, 7, 4, 8, 1, 2, 3, 4, 2, 5, 1,
            7, 4, 6, 5, 5, 0, 4, 5, 8, 5, 2, 6, 5, 4, 5, 1, 4, 3, 8, 8, 2, 9, 4,
            6, 7, 3, 3, 3, 5, 2, 5, 7, 1, 7, 0, 2, 1, 0, 1, 3, 9, 6, 3, 7, 6, 7,
            4, 5, 2, 5, 4, 5, 6, 5, 3, 0, 8, 3, 4, 7, 5, 6, 8, 4, 1, 3, 6, 0, 0,
            7, 6, 2, 4, 0, 1, 9, 5, 2, 3, 1, 0, 3, 2, 4, 7, 4, 1, 3, 8, 0, 7, 3,
            4, 3, 8, 6, 9, 8, 0, 2, 9, 2, 1, 6, 7, 5, 2, 4, 6, 9, 6, 1, 4, 3, 5,
            0, 4, 8, 9, 4, 8, 9, 9, 6, 1, 0, 4, 4, 2, 4, 6, 4, 5, 8, 9, 7, 4, 1,
            6, 2, 7, 9, 7, 6, 4, 1, 1, 5, 9, 3, 4, 8, 3, 5, 6, 3, 5, 6, 0, 8, 7,
            1, 7, 9, 8, 3, 8, 8, 2, 9, 8, 5, 9, 9, 3, 5, 7, 1, 6, 7, 8, 5, 0, 8,
            8, 9, 8, 3, 4, 1, 8, 7, 9, 9, 7, 5, 6, 2, 5, 1, 5, 5, 8, 1, 0, 5, 9,
            8, 5, 4, 8, 3, 8, 2, 2, 0, 4, 3, 3, 6, 9, 5, 2, 2, 4, 0, 7, 6, 1, 4,
            9, 9, 9, 5, 3, 8, 1, 7, 7, 3, 2, 2, 5, 7, 7, 3, 4, 0, 0, 9, 5, 1, 4,
            8, 4, 3, 3, 4, 1, 2, 9, 1, 6, 4, 4, 3, 8, 1, 3, 4, 0, 3, 7, 8, 6, 1,
            5, 9, 6, 2, 0, 5, 6, 8, 8, 5, 0, 5, 0, 3, 5, 8, 8, 3, 8, 1, 0, 0, 6,
            1, 5, 5, 3, 3, 4, 7, 8, 8, 8, 5, 4, 9, 6, 1, 3, 2, 0, 0, 1, 0, 8, 4,
            7, 0, 5, 9, 7, 5, 1, 4, 1, 0, 1, 1, 8, 1, 7, 6, 0, 8, 2, 4, 3, 5, 2,
            1, 3, 8, 6, 1, 8, 7, 7, 9, 7, 9, 6, 1, 0, 0, 9, 8, 6, 8, 4, 8, 1, 2,
            1, 0, 5, 4, 3, 8, 6, 8, 1, 7, 8, 0, 5, 7, 5, 3, 3, 1, 4, 4, 8, 2, 2,
            0, 3, 0, 1, 9, 5, 5, 3, 0, 4, 1, 8, 7, 1, 3, 9, 7, 2, 8, 3, 4, 8, 8,
            8, 4, 0, 7, 5, 4, 0, 2, 7, 7, 2, 8, 2, 9, 3, 7, 5, 5, 0, 0, 9, 9, 8,
            2, 9, 3, 8, 6, 0, 6, 0, 1, 8, 5, 3, 8, 8, 5, 4, 1, 2, 0, 2, 7, 7, 0,
            0, 1, 8, 6, 6, 6, 5, 4, 9, 6, 4, 3, 6, 7, 2, 3, 5, 1, 7, 2, 0, 8, 6,
            7, 4, 4, 1, 5, 2, 7, 1, 7, 4, 8, 5, 9, 9, 7, 1, 7, 7, 4, 1, 2, 1, 7,
            3, 0, 9, 7, 1, 1, 1, 1, 6, 4, 1, 4, 4, 4, 9, 3, 0, 5, 1, 0, 9, 6, 4,
            8, 6, 2, 2, 3, 0, 4, 5, 4, 6, 8, 1, 7, 8, 1, 4, 2, 7, 5, 7, 2, 2, 4,
            0, 1, 6, 9, 5, 4, 9, 6, 8, 7, 6, 5, 1, 4, 4, 0, 7, 9, 9, 6, 5, 4, 5,
            7, 4, 2, 5, 2, 9, 1, 1, 6, 3, 5, 1, 9, 9, 9, 4, 9, 4, 1, 2, 5, 3, 9,
            5, 8, 2, 9, 3, 6, 6, 7, 6, 1, 5, 8, 1, 1, 9, 0, 3, 3, 8, 1, 2, 7, 1,
            7, 1, 8, 7, 8, 5, 9, 4, 7, 1, 8, 7, 5, 6, 2, 5, 6, 0, 2, 9, 0, 7, 3,
            6, 4, 0, 0, 9, 2, 9, 8, 1, 3, 6, 7, 0, 6, 1, 8, 0, 1, 1, 9, 6, 6, 6,
            7, 8, 6, 5, 2, 4, 2, 9, 6, 2, 8, 8, 3, 4, 9, 0, 9, 5, 4, 6, 2, 1, 0,
            7, 9, 3, 7, 0, 2, 1, 5, 8, 4, 9, 5, 2, 5, 4, 4, 6, 6, 7, 2, 5, 2, 6,
            2, 3, 0, 8, 0, 9, 8, 7, 4, 9, 3, 9, 4, 9, 8, 0, 4, 4, 8, 6, 8, 3, 3,
            3, 0, 7, 8, 3, 3, 8, 3, 7, 4, 7, 6, 0, 3, 7, 8, 5, 6, 0, 3, 8, 0, 4,
            8, 8, 8, 4, 3, 9, 2, 3, 4, 0, 8, 7, 6, 7, 2, 1, 0, 7, 6, 9, 1, 6, 0,
            5, 7, 5, 9, 0, 4, 8, 7, 8, 2, 1, 4, 8, 2, 8, 5, 4, 3, 4, 6, 1, 2, 3,
            3, 1, 2, 2, 4, 6, 2, 3, 5, 6, 0, 5, 0, 8, 6, 7, 5, 2, 3, 4, 8, 7, 7,
            3, 8, 8, 2, 4, 8, 0, 1
          ],
          [65, 67]);

      const b = tf.tensor2d(
          [
            0, 3, 3, 3, 7, 3, 3, 3, 2, 9, 8, 4, 8, 5, 2, 5, 3, 0, 7, 0, 7, 9, 3,
            5, 7, 9, 6, 1, 0, 2, 9, 5, 6, 0, 9, 2, 6, 1, 1, 1, 6, 8, 6, 8, 8, 7,
            2, 0, 8, 5, 7, 3, 4, 7, 0, 1, 5, 8, 1, 5, 0, 3, 3, 4, 9, 1, 6, 9, 0,
            7, 9, 7, 5, 2, 6, 2, 0, 0, 3, 7, 2, 8, 8, 6, 8, 3, 6, 0, 3, 3, 2, 6,
            2, 0, 3, 5, 8, 9, 9, 1, 6, 6, 0, 3, 7, 0, 9, 9, 7, 0, 2, 9, 7, 6, 9,
            1, 1, 7, 9, 7, 2, 0, 6, 4, 2, 3, 6, 6, 3, 3, 9, 0, 1, 3, 4, 2, 2, 3,
            7, 4, 8, 4, 2, 1, 5, 5, 6, 1, 1, 2, 1, 1, 0, 7, 3, 8, 2, 8, 1, 3, 9,
            4, 8, 0, 3, 6, 7, 9, 2, 5, 4, 6, 1, 9, 6, 1, 4, 2, 3, 2, 7, 7, 0, 3,
            6, 1, 2, 8, 4, 3, 4, 1, 4, 3, 1, 3, 2, 8, 2, 5, 6, 0, 7, 0, 3, 4, 7,
            3, 9, 9, 0, 1, 0, 9, 3, 6, 5, 9, 7, 2, 3, 5, 1, 9, 3, 5, 2, 4, 5, 6,
            2, 1, 5, 5, 6, 8, 6, 0, 8, 1, 8, 6, 6, 8, 7, 6, 9, 7, 9, 4, 9, 8, 2,
            9, 8, 5, 3, 1, 3, 2, 4, 6, 4, 8, 7, 5, 3, 0, 0, 9, 1, 7, 6, 3, 1, 3,
            6, 2, 0, 2, 3, 3, 7, 1, 5, 8, 4, 6, 5, 9, 8, 8, 5, 9, 1, 0, 4, 6, 2,
            4, 9, 9, 2, 6, 6, 9, 9, 8, 9, 9, 8, 0, 5, 8, 4, 8, 3, 9, 2, 0, 6, 4,
            9, 9, 5, 5, 7, 9, 3, 3, 8, 9, 3, 2, 2, 8, 8, 8, 8, 8, 5, 2, 9, 4, 0,
            0, 2, 2, 8, 5, 1, 3, 8, 5, 6, 7, 4, 4, 0, 2, 1, 4, 9, 4, 8, 9, 6, 7,
            9, 2, 9, 6, 1, 5, 8, 4, 9, 1, 0, 0, 6, 2, 8, 5, 8, 7, 0, 5, 8, 4, 8,
            5, 4, 7, 1, 7, 9, 0, 4, 3, 5, 3, 9, 8, 7, 8, 0, 7, 8, 1, 9, 3, 6, 6,
            9, 1, 4, 6, 3, 6, 3, 2, 1, 7, 8, 3, 4, 4, 7, 0, 0, 1, 9, 0, 8, 8, 3,
            8, 8, 3, 3, 7, 0, 6, 6, 9, 9, 7, 5, 6, 4, 2, 1, 2, 0, 2, 4, 4, 3, 7,
            3, 8, 0, 9, 0, 1, 5, 0, 5, 2, 1, 5, 4, 2, 6, 0, 9, 1, 2, 1, 7, 4, 4,
            3, 9, 9, 8, 4, 4, 8, 0, 0, 9, 0, 9, 8, 7, 4, 5, 4, 4, 9, 1, 1, 9, 6,
            0, 8, 3, 4, 5, 5, 2, 1, 9, 8, 8, 0, 3, 1, 5, 7, 3, 0, 2, 7, 9, 2, 5,
            9, 1, 1, 1, 3, 1, 1, 4, 7, 3, 2, 4, 3, 3, 9, 7, 0, 9, 4, 2, 5, 6, 2,
            0, 0, 3, 2, 3, 8, 0, 7, 0, 9, 9, 0, 6, 8, 2, 7, 3, 9, 6, 5, 5, 1, 3,
            1, 9, 2, 0, 8, 3, 2, 6, 6, 8, 4, 6, 6, 1, 5, 5, 9, 0, 0, 1, 4, 0, 6,
            4, 4, 7, 4, 9, 8, 1, 6, 5, 5, 6, 3, 5, 7, 9, 2, 7, 1, 1, 5, 3, 3, 6,
            6, 9, 6, 2, 0, 1, 5, 0, 8, 7, 6, 9, 9, 1, 3, 9, 4, 5, 4, 0, 8, 3, 3,
            1, 4, 6, 7, 0, 6, 3, 8, 8, 4, 9, 8, 8, 5, 0, 8, 7, 1, 5, 0, 8, 0, 8,
            7, 0, 2, 8, 6, 3, 4, 2, 3, 6, 0, 3, 5, 7, 1, 6, 1, 8, 0, 0, 0, 4, 6,
            7, 5, 3, 2, 2, 3, 5, 9, 4, 0, 3, 5, 0, 4, 7, 4, 1, 9, 6, 9, 7, 2, 3,
            3, 3, 0, 9, 3, 1, 2, 3, 5, 9, 6, 2, 6, 8, 3, 1, 8, 1, 1, 0, 7, 3, 4,
            2, 9, 0, 6, 9, 5, 6, 2, 4, 3, 0, 5, 6, 2, 1, 4, 5, 1, 5, 2, 3, 5, 5,
            0, 5, 2, 9, 4, 4, 0, 8, 4, 3, 9, 6, 5, 9, 0, 2, 9, 3, 1, 0, 5, 9, 9,
            3, 5, 6, 0, 7, 0, 3, 6, 6, 7, 5, 2, 0, 8, 3, 6, 2, 4, 6, 5, 1, 0, 6,
            5, 6, 3, 2, 0, 8, 5, 9, 7, 7, 1, 8, 2, 6, 1, 7, 4, 2, 8, 6, 1, 3, 1,
            3, 4, 7, 2, 0, 5, 5, 6, 4, 8, 9, 2, 9, 9, 1, 4, 3, 2, 2, 3, 3, 0, 1,
            1, 0, 9, 2, 8, 3, 0, 5, 5, 6, 3, 9, 9, 2, 6, 2, 3, 8, 4, 3, 7, 7, 1,
            4, 7, 2, 4, 4, 5, 5, 8, 2, 9, 8, 4, 9, 4, 0, 9, 8, 1, 9, 6, 8, 4, 8,
            5, 6, 2, 9, 7, 3, 7, 2, 7, 9, 2, 8, 4, 3, 5, 7, 5, 1, 6, 9, 0, 0, 7,
            3, 9, 6, 0, 6, 9, 2, 9, 0, 9, 1, 8, 8, 8, 9, 4, 3, 8, 7, 8, 5, 9, 1,
            1, 9, 1, 7, 3, 3, 7, 1, 5, 5, 9, 6, 1, 8, 6, 7, 1, 9, 0, 1, 4, 4, 4,
            6, 9, 4, 7, 2, 9, 5, 9, 9, 2, 0, 5, 4, 5, 3, 7, 5, 2, 7, 4, 2, 4, 0,
            9, 0, 1, 7, 0, 3, 2, 3, 9, 9, 6, 7, 4, 6, 8, 1, 2, 5, 2, 2, 3, 4, 3,
            7, 7, 4, 6, 9, 9, 1, 6, 1, 9, 4, 5, 4, 7, 3, 0, 0, 6, 0, 7, 8, 3, 4,
            5, 6, 1, 6, 8, 0, 8, 5, 5, 7, 4, 2, 6, 0, 4, 2, 9, 7, 3, 9, 8, 6, 8,
            4, 4, 9, 1, 8, 9, 1, 3, 3, 5, 9, 5, 0, 9, 5, 5, 5, 6, 2, 1, 4, 3, 9,
            5, 1, 8, 9, 7, 8, 7, 3, 1, 9, 3, 7, 3, 2, 9, 4, 5, 8, 7, 9, 6, 7, 2,
            3, 9, 6, 2, 3, 1, 0, 2, 7, 2, 9, 2, 5, 5, 9, 4, 4, 7, 4, 4, 6, 9, 2,
            1, 8, 7, 7, 8, 8, 4, 3, 1, 6, 2, 2, 2, 8, 1, 5, 5, 5, 3, 5, 0, 8, 1,
            1, 9, 2, 9, 4, 8, 3, 4, 3, 5, 1, 2, 6, 4, 5, 6, 6, 8, 9, 1, 4, 9, 1,
            3, 1, 5, 5, 0, 1, 8, 6, 9, 3, 0, 9, 4, 7, 4, 4, 8, 5, 9, 8, 8, 4, 5,
            9, 7, 7, 0, 6, 0, 0, 7, 6, 4, 8, 2, 0, 0, 6, 8, 8, 1, 4, 7, 8, 5, 5,
            3, 9, 6, 8, 7, 8, 2, 4, 9, 0, 5, 3, 3, 5, 9, 8, 1, 9, 8, 2, 7, 2, 1,
            7, 4, 3, 5, 4, 9, 8, 1, 2, 0, 2, 7, 8, 4, 3, 2, 8, 7, 2, 6, 6, 2, 9,
            2, 9, 1, 3, 4, 8, 2, 2, 0, 8, 3, 2, 3, 9, 3, 0, 1, 3, 4, 2, 9, 5, 4,
            0, 5, 9, 4, 8, 5, 8, 4, 5, 3, 7, 2, 1, 8, 2, 8, 9, 0, 4, 3, 9, 3, 6,
            3, 5, 1, 1, 1, 0, 5, 0, 8, 2, 7, 4, 3, 4, 0, 5, 3, 4, 0, 8, 5, 3, 1,
            1, 9, 3, 1, 8, 6, 1, 2, 2, 2, 6, 8, 3, 7, 7, 8, 9, 1, 0, 1, 9, 0, 1,
            6, 7, 3, 6, 2, 7, 0, 7, 8, 2, 8, 8, 5, 0, 4, 3, 8, 5, 0, 1, 8, 0, 7,
            1, 1, 8, 3, 7, 7, 1, 6, 1, 4, 9, 3, 3, 0, 0, 0, 2, 7, 8, 6, 4, 7, 7,
            2, 0, 9, 7, 8, 4, 2, 3, 7, 2, 2, 7, 4, 0, 4, 8, 8, 8, 8, 3, 8, 4, 4,
            4, 7, 8, 0, 3, 4, 5, 8, 1, 5, 5, 7, 8, 9, 7, 1, 7, 3, 4, 3, 5, 0, 8,
            7, 1, 4, 5, 0, 6, 3, 9, 4, 4, 8, 9, 6, 3, 0, 5, 7, 1, 4, 9, 2, 0, 9,
            1, 3, 1, 2, 7, 8, 9, 6, 2, 8, 3, 4, 7, 9, 2, 7, 4, 1, 0, 7, 2, 1, 1,
            9, 5, 6, 9, 5, 8, 4, 6, 3, 1, 9, 6, 1, 9, 1, 6, 0, 4, 5, 7, 9, 3, 5,
            4, 4, 7, 2, 1, 8, 2, 7, 6, 6, 1, 8, 4, 6, 4, 7, 4, 7, 9, 9, 7, 5, 7,
            2, 4, 0, 7, 2, 3, 2, 0, 1, 0, 7, 8, 4, 1, 0, 2, 8, 8, 0, 8, 9, 9, 8,
            4, 3, 2, 4, 5, 4, 5, 5, 1, 6, 3, 6, 5, 1, 4, 9, 9, 5, 6, 0, 9, 9, 8,
            2, 6, 3, 3, 4, 1, 2, 9, 3, 7, 2, 2, 0, 7, 6, 4, 6, 7, 8, 7, 9, 8, 0,
            9, 4, 7, 2, 5, 0, 6, 7, 7, 0, 4, 0, 0, 0, 4, 1, 8, 3, 5, 9, 8, 5, 5,
            1, 4, 6, 3, 5, 3, 5, 1, 8, 5, 3, 4, 2, 8, 3, 4, 9, 1, 8, 4, 4, 4, 8,
            7, 5, 3, 0, 1, 4, 6, 3, 3, 0, 3, 1, 5, 8, 6, 6, 7, 3, 9, 9, 2, 4, 1,
            1, 9, 9, 5, 1, 9, 4, 9, 4, 7, 2, 8, 0, 6, 0, 3, 7, 2, 7, 6, 9, 6, 8,
            5, 8, 9, 7, 4, 1, 5, 5, 2, 7, 8, 6, 6, 7, 3, 6, 9, 1, 9, 4, 9, 9, 2,
            6, 3, 2, 9, 8, 9, 4, 8, 3, 0, 5, 9, 9, 2, 1, 7, 2, 2, 1, 8, 8, 7, 0,
            9, 8, 8, 0, 8, 4, 3, 2, 2, 7, 9, 9, 7, 5, 8, 9, 8, 7, 4, 7, 9, 1, 0,
            7, 6, 2, 4, 4, 0, 1, 9, 7, 4, 5, 9, 2, 2, 5, 1, 3, 2, 2, 9, 2, 2, 8,
            7, 6, 0, 7, 5, 6, 5, 6, 0, 0, 5, 6, 7, 2, 7, 1, 2, 1, 7, 0, 0, 2, 6,
            3, 8, 1, 7, 1, 8, 7, 7, 5, 1, 0, 8, 4, 7, 8, 9, 1, 5, 4, 1, 9, 3, 3,
            8, 4, 5, 7, 9, 4, 7, 3, 8, 9, 5, 3, 2, 7, 3, 9, 7, 9, 8, 2, 8, 0, 1,
            7, 8, 2, 1, 0, 7, 5, 1, 3, 7, 2, 4, 8, 8, 4, 6, 8, 2, 7, 6, 8, 2, 0,
            9, 5, 4, 0, 2, 2, 1, 1, 4, 4, 9, 3, 0, 7, 1, 6, 4, 4, 9, 9, 2, 3, 6,
            3, 8, 7, 3, 3, 1, 0, 0, 1, 9, 6, 7, 5, 5, 8, 4, 1, 3, 6, 3, 6, 5, 6,
            3, 7, 8, 1, 4, 0, 0, 2, 4, 1, 3, 6, 8, 1, 2, 9, 3, 9, 7, 8, 4, 0, 6,
            4, 3, 3, 9, 8, 9, 1, 7, 1, 5, 8, 1, 4, 3, 2, 0, 6, 5, 9, 2, 6, 2, 5,
            8, 8, 8, 0, 7, 4, 1, 1, 3, 6, 0, 8, 3, 6, 2, 4, 6, 1, 7, 5, 3, 8, 0,
            6, 3, 7, 5, 5, 2, 3, 2, 7, 6, 9, 3, 8, 4, 5, 5, 4, 0, 9, 9, 7, 8, 6,
            7, 1, 8, 7, 1, 5, 0, 0, 9, 5, 8, 7, 7, 3, 4, 2, 1, 4, 1, 9, 1, 1, 9,
            8, 6, 3, 5, 5, 0, 8, 9, 1, 7, 5, 1, 7, 8, 0, 0, 4, 0, 3, 7, 1, 4, 4,
            7, 4, 3, 3, 8, 7, 1, 5, 1, 1, 0, 9, 5, 0, 5, 9, 7, 0, 5, 7, 4, 6, 0,
            2, 4, 0, 4, 8, 1, 6, 1, 5, 7, 5, 5, 1, 8, 2, 3, 8, 5, 8, 8, 9, 0, 4,
            1, 2, 5, 9, 0, 0, 8, 1, 7, 4, 8, 8, 3, 3, 2, 4, 8, 1, 7, 6, 0, 1, 6,
            6, 7, 1, 5, 9, 1, 7, 8, 1, 5, 9, 5, 8, 2, 4, 6, 0, 3, 4, 2, 3, 8, 4,
            4, 9, 7, 3, 7, 3, 8, 9, 1, 7, 2, 2, 6, 5, 1, 9, 2, 8, 1, 6, 4, 3, 1,
            0, 6, 4, 3, 1, 0, 5, 0, 5, 9, 9, 2, 7, 1, 0, 0, 3, 4, 7, 1, 5, 9, 2,
            8, 7, 8, 0, 9, 0, 8, 8, 6, 8, 3, 1, 3, 5, 4, 3, 9, 5, 2, 5, 5, 1, 2,
            4, 7, 8, 3, 1, 9, 2, 4, 9, 1, 2, 8, 9, 9, 6, 1, 5, 8, 8, 4, 2, 3, 8,
            3, 8, 7, 0, 7, 0, 1, 6, 3, 2, 5, 0, 0, 5, 6, 0, 6, 8, 4, 9, 9, 3, 8,
            5, 7, 3, 5, 4, 7, 3, 4, 7, 8, 2, 3, 8, 5, 1, 4, 3, 4, 8, 0, 7, 5, 8,
            5, 4, 0, 7, 0, 7, 2, 2, 0, 0, 0, 1, 6, 9, 8, 2, 9, 5, 1, 2, 9, 3, 9,
            1, 7, 3, 7, 2, 9, 8, 6, 1, 7, 2, 4, 2, 3, 2, 7, 8, 0, 0, 9, 0, 8, 2,
            1, 1, 7, 6, 7, 5, 4, 7, 0, 2, 8, 4, 8, 2, 0, 0, 5, 5, 3, 6, 5, 9, 4,
            6, 1, 6, 1, 1, 3, 6, 2, 5, 4, 1, 7, 6, 9, 7, 4, 6, 2, 7, 8, 0, 8, 6,
            7, 0, 3, 8, 7, 4, 0, 8, 4, 9, 0, 1, 6, 8, 7, 4, 2, 7, 8, 5, 2, 9, 4,
            4, 2, 0, 2, 8, 0, 8, 1, 2, 4, 1, 3, 1, 8, 2, 9, 8, 6, 9, 6, 5, 1, 9,
            5, 4, 2, 1, 5, 9, 2, 2, 2, 6, 4, 4, 8, 4, 0, 1, 4, 2, 7, 4, 6, 1, 8,
            8, 3, 4, 1, 6, 2, 2, 4, 9, 5, 8, 5, 2, 7, 0, 9, 4, 5, 2, 3, 2, 4, 8,
            0, 3, 3, 4, 4, 0, 3, 6, 8, 6, 4, 3, 1, 9, 9, 8, 0, 3, 3, 5, 0, 6, 8,
            4, 0, 2, 5, 7, 0, 0, 5, 8, 2, 5, 3, 5, 9, 5, 8, 3, 9, 5, 0, 6, 7, 9,
            4, 5, 8, 7, 8, 9, 8, 2, 9, 0, 4, 6, 5, 5, 8, 9, 7, 7, 7, 4, 9, 3, 9,
            3, 4, 0, 9, 3, 5, 3, 4, 3, 9, 3, 4, 1, 3, 5, 8, 0, 6, 8, 1, 3, 6, 5,
            5, 9, 9, 6, 9, 7, 8, 2, 6, 0, 4, 3, 3, 7, 2, 9, 2, 3, 6, 0, 3, 0, 2,
            7, 4, 5, 2, 3, 5, 7, 9, 9, 8, 0, 9, 3, 1, 6, 1, 7, 6, 4, 9, 0, 8, 5,
            8, 8, 4, 3, 1, 5, 8, 4, 8, 0, 3, 8, 3, 2, 8, 7, 9, 0, 0, 3, 3, 4, 5,
            2, 5, 7, 3, 7, 8, 1, 7, 1, 6, 6, 7, 7, 8, 8, 1, 2, 2, 7, 6, 6, 7, 2,
            6, 8, 7, 1, 6, 2, 5, 9, 9, 1, 3, 7, 1, 0, 6, 3, 8, 5, 9, 8, 3, 3, 9,
            0, 8, 4, 0, 6, 0, 6, 1, 9, 2, 7, 5, 7, 5, 2, 3, 6, 2, 7, 4, 6, 3, 9,
            5, 4, 7, 3, 1, 7, 4, 6, 3, 4, 3, 1, 9, 7, 5, 2, 0, 9, 1, 6, 3, 9, 1,
            9, 8, 0, 7, 0, 9, 9, 1, 2, 2, 4, 1, 5, 7, 7, 5, 7, 8, 2, 6, 0, 9, 3,
            9, 8, 6, 4, 4, 7, 4, 0, 6, 0, 3, 0, 9, 4, 6, 8, 9, 4, 2, 8, 5, 7, 9,
            3, 5, 3, 1, 1, 7, 2, 5, 7, 1, 6, 2, 6, 5, 5, 9, 1, 4, 4, 8, 6, 8, 1,
            2, 8, 6, 7, 1, 8, 7, 6, 9, 4, 6, 4, 1, 8, 9, 9, 4, 6, 3, 1, 0, 1, 4,
            7, 8, 1, 0, 4, 6, 5, 6, 4, 2, 8, 8, 0, 3, 8, 6, 6, 1, 2, 8, 7, 6, 8,
            6, 0, 4, 2, 2, 7, 9, 4, 3, 2, 7, 7, 5, 1, 5, 5, 6, 6, 2, 7, 2, 0, 3,
            7, 2, 5, 7, 1, 2, 8, 6, 6, 7, 8, 1, 0, 0, 1, 9, 7, 8, 7, 1, 2, 6, 1,
            8, 4, 2, 6, 5, 1, 5, 7, 7, 7, 3, 3, 0, 8, 7, 9, 9, 8, 9, 8, 3, 3, 1,
            9, 9, 1, 9, 2, 5, 2, 2, 7, 8, 7, 3, 0, 2, 3, 4, 8, 6, 4, 2, 8, 8, 0,
            8, 9, 3, 1, 1, 0, 9, 5, 1, 3, 7, 4, 8, 7, 3, 7, 8, 0, 1, 1, 9, 4, 3,
            9, 7, 3, 4, 1, 8, 5, 2, 9, 1, 6, 8, 6, 3, 2, 1, 4, 8, 9, 7, 9, 2, 1,
            6, 8, 9, 0, 2, 3, 9, 6, 1, 4, 0, 2, 2, 2, 3, 5, 5, 4, 0, 2, 7, 8, 2,
            5, 9, 3, 9, 5, 0, 5, 2, 8, 5, 7, 5, 2, 3, 5, 4, 2, 9, 4, 1, 0, 7, 0,
            7, 3, 1, 3, 8, 8, 3, 2, 2, 1, 4, 8, 8, 3, 9, 7, 4, 2, 6, 4, 8, 1, 6,
            3, 3, 2, 3, 0, 2, 0, 0, 3, 8, 9, 1, 7, 7, 5, 5, 2, 7, 6, 7, 7, 0, 2,
            8, 1, 5, 0, 7, 9, 3, 9, 6, 8, 7, 1, 3, 6, 8, 4, 7, 8, 2, 9, 8, 9, 2,
            3, 9, 4, 8, 8, 9, 4, 7, 1, 3, 9, 2, 4, 8, 8, 2, 8, 1, 3, 2, 3, 6, 6,
            4, 7, 5, 3, 9, 2, 0, 8, 2, 9, 9, 0, 5, 5, 3, 5, 5, 6, 7, 0, 3, 0, 6,
            5, 8, 7, 0, 4, 3, 9, 7, 7, 1, 2, 2, 8, 8, 4, 3, 1, 8, 7, 2, 7, 2, 6,
            5, 6, 4, 7, 8, 0, 6, 6, 2, 3, 0, 3, 3, 7, 2, 6, 9, 7, 6, 4, 8, 5, 5,
            9, 3, 7, 9, 5, 3, 1, 1, 9, 2, 4, 8, 1, 7, 3, 5, 9, 8, 5, 6, 6, 5, 7,
            5, 7, 4, 5, 6, 1, 2, 7, 9, 0, 6, 0, 2, 3, 9, 8, 7, 4, 3, 1, 2, 4, 9,
            7, 4, 8, 3, 0, 3, 2, 7, 7, 0, 0, 7, 2, 0, 6, 0, 2, 9, 2, 6, 5, 7, 8,
            9, 8, 3, 4, 7, 2, 0, 0, 7, 5, 9, 9, 6, 7, 5, 2, 7, 4, 2, 9, 6, 6, 3,
            1, 2, 0, 8, 3, 2, 8, 0, 5, 1, 0, 9, 1, 6, 3, 1, 3, 7, 7, 5, 7, 4, 4,
            4, 1, 9, 2, 6, 7, 1, 3, 6, 2, 5, 8, 2, 4, 0, 7, 4, 3, 6, 7, 4, 9, 4,
            9, 5, 0, 5, 1, 0, 0, 9, 1, 4, 8, 2, 9, 6, 7, 5, 3, 5, 0, 8, 3, 4, 0,
            7, 5, 8, 5, 9, 4, 0, 2, 7, 1, 9, 9, 6, 1, 2, 8, 5, 7, 8, 5, 0, 4, 9,
            6, 7, 6, 6, 5, 6, 2, 6, 8, 0, 9, 7, 3, 3, 3, 4, 6, 5, 9, 0, 1, 6, 8,
            9, 3, 3, 9, 2, 0, 2, 1, 0, 0, 8, 7, 6, 3, 4, 4, 9, 7, 5, 8, 5, 1, 5,
            2, 3, 6, 2, 0, 9, 1, 3, 0, 3, 3, 6, 9, 4, 2, 0, 2, 3, 1, 9, 0, 2, 5,
            2, 0, 8, 6, 0, 9, 8, 8, 8, 3, 1, 4, 5, 0, 3, 0, 4, 5, 4, 9, 2, 8, 2,
            1, 9, 0, 8, 2, 2, 3, 2, 5, 6, 3, 1, 5, 1, 9, 0, 4, 6, 4, 4, 8, 3, 8,
            9, 9, 3, 9, 9, 2, 2, 1, 7, 3, 8, 7, 6, 9, 0, 4, 2, 7, 8, 4, 9, 3, 1,
            3, 6, 1, 3, 7, 8, 0, 5, 7, 3, 3, 2, 8, 9, 4, 8, 6, 6, 9, 4, 2, 5, 7,
            9, 3, 8, 2, 5, 6, 9, 3, 4, 3, 3, 2, 0, 0, 4, 7, 7, 5, 9, 5, 5, 6, 9,
            4, 9, 3, 1, 5, 3, 1, 5, 3, 2, 2, 3, 4, 4, 7, 5, 0, 5, 4, 3, 3, 2, 1,
            4, 1, 8, 5, 1, 7, 7, 7, 8, 6, 5, 2, 3, 2, 1, 3, 1, 0, 2, 0, 9, 8, 6,
            5, 3, 4, 6, 6, 7, 5, 8, 1, 4, 8, 1, 4, 5, 7, 2, 1, 9, 1, 7, 1, 4, 5,
            9, 8, 3, 1, 3, 8, 6, 3, 0, 0, 0, 6, 7, 4, 3, 4, 3, 6, 5, 0, 9, 0, 9,
            4, 2, 8, 4, 1, 7, 3, 9, 7, 6, 5, 2, 8, 0, 8, 3, 8, 6, 2, 3, 3, 0, 8,
            0, 2, 9, 7, 7, 1, 4, 7, 3, 8, 2, 0, 1, 6, 2, 4, 1, 5, 1, 2, 7, 2, 0,
            3, 1, 6, 0, 4, 4, 5, 5, 6, 6, 5, 1, 7, 7, 0, 8, 6, 3, 5, 8, 4, 4, 8,
            2, 6, 3, 8, 1, 2, 9, 4, 3, 7, 4, 2, 9, 4, 0, 1, 4, 7, 8, 0, 3, 1, 2,
            0, 8, 5, 6, 5, 7, 6, 3, 9, 8, 7, 1, 2, 4, 2, 4, 2, 2, 3, 2, 3, 3, 2,
            5, 7, 5, 5, 1, 0, 6, 2, 2, 3, 6, 3, 3, 4, 2, 1, 8, 4, 2, 8, 7, 6, 1,
            2, 2, 5, 9, 7, 1, 5, 2, 8, 6, 5, 5, 1, 7, 2, 6, 5, 7, 8, 3, 3, 5, 8,
            6, 4, 8, 0, 0, 4, 2, 6, 3, 2, 8, 3, 1, 6, 8, 4, 8, 9, 3, 8, 3, 3, 6,
            5, 3, 4, 9, 0, 3, 4, 2, 8, 1, 9, 8, 0, 6, 6, 5, 7, 9, 3, 0, 3, 9, 2,
            9, 1, 1, 3, 2, 7, 7, 6, 8, 2, 8, 9, 0, 6, 2, 5, 1, 6, 5, 7, 9, 2, 1,
            2, 1, 3, 8, 2, 9, 9, 8, 0, 4, 7, 3, 6, 3, 8, 4, 4, 3, 9, 7, 1, 5, 0,
            1, 3, 4, 7, 0, 6, 9, 6, 2, 1, 1, 2, 3, 2, 0, 9, 8, 8, 2, 9, 4, 8, 1,
            7, 9, 7, 8, 2, 6, 2, 5, 6, 1, 5, 7, 4, 4, 4, 4, 0, 1, 4, 9, 1, 5, 4,
            4, 7, 1, 8, 3, 3, 8, 6, 9, 4, 4, 0, 6, 6, 9, 4, 2, 8, 5, 6, 7, 2, 3,
            2, 2, 9, 9, 7, 6, 1, 4, 0, 2, 4, 4, 7, 2, 2, 7, 5, 5, 4, 1, 9, 0, 9,
            4, 1, 8, 6, 9, 6, 3, 6, 4, 9, 5, 1, 0, 4, 0, 4, 6, 7, 1, 6, 3, 3, 1,
            5, 3, 7, 7, 4, 4, 7, 4, 3, 5, 5, 9, 6, 3, 3, 3, 6, 8, 3, 5, 7, 2, 7,
            6, 4, 3, 1, 6, 8, 8, 4, 9, 5, 9, 1, 0, 4, 8, 5, 7, 5, 7, 1, 8, 2, 3,
            1, 5, 1, 9, 7, 9, 0, 3, 9, 3, 2, 5, 1, 9, 9, 9, 9, 4, 8, 7, 4, 2, 4,
            9, 3, 4, 6, 7, 9, 0, 0, 3, 6, 9, 8, 1, 8, 1, 9, 1, 5, 1, 3, 5, 2, 4,
            8, 8, 7, 8, 0, 3, 0, 6, 9, 4, 5, 9, 3, 8, 8, 7, 9, 7, 9, 7, 6, 7, 5,
            5, 4, 0, 9, 9, 1, 0, 7, 5, 9, 7, 8, 0, 2, 0, 2, 4, 4, 0, 4, 7, 5, 1,
            9, 7, 1, 2, 6, 7, 4, 1, 5, 8, 6, 8, 6, 6, 1, 9, 4, 4, 9, 9, 7, 6, 8,
            4, 9, 3, 6, 6, 1, 1, 9, 6, 9, 1, 9, 2, 5, 1, 5, 6, 0, 1, 1, 2, 1, 1,
            6, 8, 6, 6, 9, 1, 6, 1, 3, 2, 2, 5, 4, 2, 6, 0, 2, 2, 5, 0, 1, 2, 5,
            4, 7, 2, 4, 8, 6, 5, 0, 8, 1, 0, 8, 1, 4, 3, 9, 0, 6, 3, 7, 3, 4, 5,
            6, 0, 9, 7, 3, 1, 5, 7, 8, 0, 3, 2, 9, 3, 0, 3, 3, 1, 6, 4, 0, 6, 9,
            4, 9, 9, 1, 9, 6, 7, 3, 3, 3, 5, 8, 8, 9, 3, 6, 9, 1, 7, 1, 5, 8, 4,
            2, 3, 8, 7, 1, 3, 4, 0, 7, 5, 5, 5, 1, 4, 4, 2, 7, 8, 1, 9, 3, 1, 5,
            9, 6, 0, 6, 4, 7, 2, 1, 2, 3, 2, 4, 5, 6, 1, 5, 0, 1, 2, 7, 2, 5, 7,
            6, 9, 9, 5, 9, 4, 5, 4, 1, 4, 0, 3, 9, 9, 1, 0, 4, 5, 4, 7, 7, 1, 0,
            3, 5, 3, 5, 0, 9, 9, 7, 8, 9, 3, 0, 2, 0, 5, 3, 1, 3, 4, 0, 2, 6, 4,
            6, 4, 7, 4, 1, 8, 4, 8, 6, 1, 1, 0, 2, 3, 0, 5, 1, 9, 2, 1, 0, 9, 3,
            0, 0, 4, 4, 7, 5
          ],
          [67, 66]);

      const c = tf.matMul(a, b);
      const cData = await c.data();

      expect(c.shape).toEqual([65, 66]);
      test_util.expectArraysClose(cData, [
        1017, 1086, 958,  925,  1117, 1018, 1092, 1180, 1055, 1141, 1061, 970,
        1200, 969,  1066, 1007, 1241, 909,  980,  1141, 1084, 889,  971,  1042,
        1087, 985,  1019, 929,  1112, 1239, 1155, 966,  984,  1154, 1146, 1117,
        1264, 1059, 960,  1265, 1024, 1071, 1288, 1086, 1219, 1070, 1168, 962,
        1098, 1041, 937,  1002, 1102, 1110, 940,  1120, 1028, 1062, 1162, 1049,
        904,  1065, 1056, 1230, 853,  1013, 1579, 1519, 1552, 1377, 1478, 1375,
        1397, 1820, 1672, 1626, 1633, 1374, 1514, 1420, 1371, 1357, 1689, 1346,
        1378, 1497, 1424, 1387, 1495, 1601, 1455, 1594, 1716, 1375, 1459, 1523,
        1601, 1615, 1583, 1462, 1669, 1600, 1879, 1527, 1370, 1692, 1496, 1541,
        1894, 1470, 1784, 1530, 1792, 1410, 1615, 1713, 1465, 1420, 1671, 1637,
        1472, 1473, 1421, 1389, 1638, 1330, 1329, 1531, 1475, 1720, 1592, 1416,
        1759, 1748, 1467, 1582, 1749, 1484, 1636, 1844, 1601, 1643, 1683, 1514,
        1721, 1438, 1580, 1511, 1716, 1480, 1477, 1671, 1765, 1478, 1577, 1617,
        1638, 1612, 1633, 1449, 1690, 1733, 1758, 1591, 1810, 1655, 1911, 1447,
        1939, 1687, 1401, 1655, 1669, 1624, 2213, 1648, 1867, 1745, 1872, 1551,
        1799, 1824, 1505, 1542, 1635, 1826, 1590, 1596, 1598, 1416, 1645, 1470,
        1352, 1511, 1773, 1780, 1593, 1534, 1424, 1329, 1326, 1238, 1426, 1276,
        1175, 1584, 1398, 1429, 1525, 1254, 1505, 1137, 1213, 1242, 1575, 1174,
        1169, 1379, 1433, 1121, 1357, 1371, 1322, 1193, 1412, 1197, 1294, 1392,
        1362, 1403, 1576, 1291, 1458, 1340, 1664, 1247, 1186, 1359, 1283, 1290,
        1624, 1326, 1520, 1423, 1613, 1339, 1417, 1480, 1399, 1185, 1427, 1356,
        1397, 1303, 1248, 1208, 1419, 1125, 1158, 1330, 1203, 1532, 1220, 1325,
        1231, 1121, 1095, 974,  1179, 953,  1085, 1392, 1102, 1154, 1314, 1045,
        1204, 999,  1059, 1089, 1305, 1053, 973,  1190, 1200, 937,  1097, 1184,
        1143, 1131, 1182, 1121, 1219, 1233, 1134, 1251, 1063, 1151, 1209, 1144,
        1362, 1261, 1026, 1398, 1007, 1093, 1363, 1082, 1316, 1070, 1237, 1068,
        1220, 1238, 1094, 1076, 1152, 1202, 1114, 1221, 1159, 1184, 1200, 983,
        905,  1127, 1203, 1310, 924,  1198, 1435, 1411, 1119, 1250, 1485, 1265,
        1245, 1584, 1370, 1411, 1452, 1162, 1425, 1150, 1254, 1227, 1508, 1200,
        1171, 1468, 1419, 1218, 1239, 1186, 1198, 1255, 1368, 1223, 1478, 1354,
        1299, 1267, 1336, 1300, 1620, 1226, 1577, 1435, 1317, 1482, 1259, 1231,
        1568, 1326, 1524, 1329, 1477, 1231, 1404, 1388, 1254, 1184, 1301, 1414,
        1385, 1393, 1283, 1292, 1357, 1211, 1062, 1243, 1309, 1487, 1240, 1286,
        1508, 1506, 1214, 1284, 1419, 1317, 1234, 1545, 1556, 1442, 1439, 1175,
        1441, 1304, 1355, 1308, 1519, 1154, 1267, 1275, 1411, 1240, 1460, 1292,
        1292, 1197, 1451, 1181, 1371, 1391, 1339, 1293, 1392, 1465, 1514, 1363,
        1644, 1279, 1137, 1500, 1311, 1502, 1699, 1402, 1518, 1464, 1522, 1181,
        1545, 1604, 1299, 1460, 1273, 1425, 1256, 1251, 1342, 1278, 1416, 1213,
        1231, 1246, 1322, 1521, 1200, 1295, 1665, 1411, 1342, 1406, 1607, 1287,
        1335, 1776, 1378, 1636, 1504, 1329, 1573, 1227, 1453, 1305, 1655, 1318,
        1224, 1443, 1547, 1345, 1425, 1369, 1400, 1191, 1581, 1284, 1484, 1511,
        1430, 1342, 1553, 1520, 1580, 1386, 1709, 1419, 1258, 1477, 1379, 1567,
        1765, 1446, 1611, 1399, 1693, 1281, 1469, 1561, 1331, 1398, 1403, 1473,
        1353, 1394, 1426, 1348, 1403, 1235, 1166, 1333, 1390, 1653, 1174, 1298,
        1620, 1389, 1235, 1201, 1390, 1262, 1361, 1576, 1483, 1387, 1324, 1099,
        1354, 1125, 1234, 1196, 1394, 1142, 1135, 1366, 1253, 1085, 1226, 1238,
        1221, 1155, 1295, 1242, 1355, 1375, 1379, 1277, 1474, 1359, 1552, 1296,
        1469, 1220, 1141, 1337, 1206, 1230, 1476, 1198, 1483, 1465, 1536, 1115,
        1447, 1378, 1203, 1311, 1280, 1305, 1345, 1361, 1277, 1292, 1220, 1231,
        1135, 1270, 1280, 1362, 1185, 1240, 1250, 1243, 1229, 1124, 1187, 1209,
        1044, 1315, 1281, 1378, 1319, 1148, 1331, 1043, 1075, 1152, 1410, 1077,
        1234, 1224, 1159, 1124, 1192, 1244, 1225, 1205, 1436, 1178, 1158, 1239,
        1225, 1214, 1334, 1206, 1427, 1202, 1473, 1268, 1066, 1366, 1225, 1302,
        1523, 1167, 1418, 1158, 1397, 1043, 1281, 1254, 1078, 1199, 1326, 1370,
        1295, 1212, 1054, 1196, 1233, 1148, 1066, 1250, 1185, 1411, 1196, 1096,
        1375, 1351, 1218, 1097, 1459, 1128, 1351, 1564, 1357, 1400, 1371, 1180,
        1343, 1277, 1168, 1242, 1487, 1079, 1065, 1292, 1304, 1169, 1262, 1131,
        1224, 1213, 1317, 1118, 1298, 1396, 1314, 1160, 1294, 1368, 1568, 1263,
        1668, 1198, 981,  1346, 1113, 1362, 1544, 1403, 1545, 1254, 1492, 1206,
        1403, 1467, 1234, 1263, 1216, 1249, 1214, 1370, 1332, 1327, 1287, 1101,
        1083, 1192, 1464, 1396, 1112, 1380, 1572, 1428, 1350, 1355, 1516, 1294,
        1407, 1742, 1510, 1569, 1602, 1191, 1450, 1302, 1421, 1338, 1574, 1213,
        1125, 1440, 1362, 1199, 1307, 1322, 1422, 1449, 1479, 1335, 1427, 1526,
        1547, 1321, 1502, 1483, 1598, 1440, 1669, 1406, 1233, 1483, 1331, 1409,
        1575, 1450, 1561, 1422, 1530, 1231, 1587, 1621, 1258, 1295, 1338, 1465,
        1495, 1489, 1454, 1504, 1375, 1264, 1249, 1235, 1371, 1548, 1235, 1260,
        1578, 1523, 1356, 1263, 1589, 1304, 1291, 1747, 1575, 1527, 1549, 1407,
        1424, 1201, 1369, 1408, 1645, 1203, 1322, 1370, 1488, 1225, 1387, 1362,
        1296, 1398, 1553, 1328, 1459, 1621, 1399, 1497, 1568, 1522, 1556, 1517,
        1872, 1516, 1257, 1576, 1393, 1467, 1766, 1468, 1617, 1512, 1512, 1312,
        1678, 1615, 1444, 1448, 1438, 1550, 1513, 1298, 1487, 1466, 1514, 1263,
        1266, 1271, 1474, 1747, 1270, 1418, 1704, 1559, 1474, 1575, 1725, 1490,
        1461, 1846, 1711, 1777, 1693, 1471, 1652, 1478, 1447, 1557, 1734, 1361,
        1398, 1645, 1604, 1397, 1644, 1460, 1488, 1497, 1639, 1450, 1546, 1625,
        1611, 1644, 1671, 1655, 1753, 1536, 1912, 1628, 1449, 1774, 1562, 1618,
        1928, 1526, 1843, 1649, 1800, 1510, 1694, 1791, 1477, 1531, 1564, 1718,
        1643, 1452, 1569, 1442, 1670, 1525, 1425, 1476, 1623, 1747, 1486, 1595,
        1248, 1134, 1095, 972,  1315, 1142, 1148, 1371, 1321, 1256, 1176, 1080,
        1188, 1024, 1138, 1098, 1351, 1086, 1039, 1286, 1181, 892,  975,  1051,
        1118, 1131, 1258, 1088, 1197, 1231, 1238, 994,  1228, 1203, 1176, 1218,
        1446, 1103, 1053, 1160, 1056, 1068, 1314, 1191, 1275, 1269, 1291, 1075,
        1228, 1265, 1185, 1204, 1111, 1287, 1124, 1257, 1115, 1196, 1051, 981,
        1001, 1261, 1155, 1245, 1051, 1148, 1350, 1655, 1178, 1205, 1437, 1279,
        1376, 1558, 1514, 1487, 1483, 1280, 1492, 1181, 1209, 1460, 1621, 1113,
        1453, 1345, 1425, 1138, 1307, 1335, 1380, 1369, 1429, 1251, 1365, 1479,
        1469, 1342, 1461, 1258, 1722, 1327, 1687, 1380, 1233, 1386, 1341, 1386,
        1641, 1441, 1515, 1497, 1570, 1275, 1566, 1550, 1290, 1408, 1483, 1568,
        1340, 1378, 1353, 1363, 1272, 1241, 1227, 1266, 1557, 1501, 1354, 1345,
        1440, 1161, 1078, 1038, 1201, 1212, 1115, 1370, 1272, 1340, 1242, 1054,
        1261, 931,  1079, 1078, 1378, 1039, 1018, 1073, 1285, 991,  1110, 1133,
        1119, 997,  1212, 1060, 1122, 1303, 1114, 1206, 1330, 1235, 1266, 1165,
        1395, 1046, 1052, 1124, 1183, 1131, 1495, 1132, 1310, 1250, 1293, 1200,
        1218, 1193, 1060, 1139, 1208, 1298, 1317, 1053, 1086, 1079, 1120, 1006,
        1070, 1108, 1159, 1322, 985,  1136, 1524, 1463, 1256, 1184, 1500, 1327,
        1405, 1638, 1388, 1430, 1444, 1176, 1537, 1318, 1180, 1245, 1594, 1107,
        1070, 1370, 1322, 1272, 1309, 1325, 1465, 1258, 1487, 1339, 1404, 1587,
        1466, 1395, 1427, 1467, 1601, 1377, 1794, 1464, 1106, 1529, 1206, 1482,
        1660, 1415, 1680, 1351, 1658, 1304, 1435, 1596, 1260, 1319, 1378, 1387,
        1400, 1406, 1397, 1327, 1561, 1345, 1131, 1272, 1510, 1472, 1181, 1443,
        1491, 1531, 1197, 1316, 1411, 1354, 1403, 1749, 1527, 1462, 1493, 1290,
        1571, 1331, 1162, 1305, 1458, 1271, 1269, 1367, 1448, 1107, 1377, 1314,
        1331, 1333, 1375, 1366, 1412, 1537, 1480, 1293, 1423, 1420, 1601, 1243,
        1804, 1414, 1279, 1431, 1413, 1392, 1804, 1420, 1630, 1359, 1579, 1302,
        1557, 1609, 1430, 1263, 1343, 1480, 1324, 1517, 1437, 1213, 1466, 1322,
        1262, 1352, 1555, 1436, 1238, 1477, 1546, 1674, 1285, 1258, 1479, 1313,
        1358, 1631, 1482, 1504, 1530, 1354, 1575, 1221, 1376, 1298, 1658, 1189,
        1237, 1485, 1489, 1310, 1366, 1486, 1493, 1446, 1520, 1335, 1522, 1539,
        1647, 1452, 1474, 1498, 1815, 1379, 1763, 1537, 1363, 1582, 1335, 1341,
        1827, 1449, 1611, 1515, 1611, 1328, 1594, 1618, 1361, 1347, 1524, 1630,
        1521, 1509, 1447, 1298, 1568, 1349, 1259, 1320, 1590, 1690, 1301, 1392,
        1548, 1330, 1358, 1253, 1601, 1308, 1364, 1610, 1476, 1547, 1485, 1290,
        1564, 1083, 1348, 1145, 1482, 1172, 1212, 1272, 1545, 1226, 1316, 1378,
        1328, 1273, 1417, 1211, 1304, 1404, 1395, 1335, 1530, 1552, 1600, 1395,
        1528, 1330, 1260, 1402, 1288, 1405, 1762, 1336, 1495, 1487, 1400, 1337,
        1521, 1490, 1204, 1326, 1362, 1521, 1447, 1251, 1320, 1343, 1483, 1258,
        1073, 1324, 1438, 1557, 1247, 1255, 1541, 1590, 1368, 1439, 1673, 1432,
        1545, 1754, 1526, 1555, 1574, 1355, 1641, 1368, 1523, 1466, 1738, 1378,
        1319, 1694, 1605, 1289, 1527, 1396, 1491, 1268, 1520, 1423, 1547, 1672,
        1586, 1487, 1640, 1597, 1761, 1497, 1831, 1477, 1291, 1750, 1398, 1467,
        1912, 1509, 1732, 1555, 1734, 1354, 1625, 1596, 1400, 1428, 1588, 1584,
        1557, 1535, 1529, 1450, 1563, 1544, 1309, 1516, 1582, 1660, 1412, 1317,
        1238, 1298, 1211, 1321, 1435, 1212, 1218, 1685, 1275, 1379, 1385, 1214,
        1436, 1289, 1298, 1102, 1498, 1175, 1127, 1497, 1508, 1267, 1307, 1357,
        1330, 1335, 1438, 1127, 1374, 1441, 1279, 1375, 1413, 1289, 1377, 1323,
        1622, 1468, 1121, 1406, 1389, 1246, 1665, 1427, 1511, 1402, 1584, 1283,
        1393, 1325, 1158, 1219, 1421, 1358, 1380, 1430, 1261, 1234, 1448, 1066,
        1037, 1192, 1370, 1480, 1300, 1296, 1378, 1382, 1300, 1243, 1254, 1325,
        1216, 1541, 1417, 1472, 1382, 1139, 1390, 1134, 1231, 1234, 1539, 1151,
        1300, 1322, 1408, 1149, 1190, 1198, 1321, 1288, 1522, 1226, 1310, 1471,
        1408, 1253, 1301, 1401, 1563, 1203, 1568, 1376, 1231, 1465, 1256, 1250,
        1565, 1369, 1517, 1334, 1501, 1121, 1494, 1462, 1191, 1292, 1257, 1490,
        1300, 1374, 1312, 1330, 1414, 1261, 1144, 1370, 1345, 1485, 1256, 1217,
        1326, 1396, 1122, 1061, 1434, 1331, 1255, 1483, 1400, 1373, 1299, 1049,
        1382, 1213, 1148, 1297, 1493, 1072, 1131, 1346, 1333, 1124, 1228, 1302,
        1303, 1364, 1332, 1205, 1225, 1497, 1301, 1323, 1370, 1245, 1595, 1253,
        1561, 1303, 1146, 1298, 1197, 1275, 1478, 1258, 1444, 1447, 1529, 1252,
        1429, 1345, 1255, 1269, 1344, 1373, 1341, 1393, 1265, 1255, 1267, 1192,
        1081, 1266, 1280, 1393, 1233, 1315, 1449, 1368, 1300, 1266, 1373, 1245,
        1280, 1623, 1384, 1554, 1432, 1176, 1451, 1283, 1370, 1104, 1390, 1101,
        1143, 1336, 1441, 1339, 1422, 1415, 1483, 1312, 1499, 1260, 1257, 1384,
        1324, 1351, 1391, 1392, 1474, 1338, 1513, 1310, 1147, 1528, 1253, 1241,
        1701, 1310, 1501, 1409, 1467, 1155, 1400, 1499, 1203, 1231, 1252, 1378,
        1335, 1333, 1238, 1188, 1423, 1209, 1105, 1304, 1452, 1556, 1258, 1178,
        1272, 1456, 1125, 1095, 1353, 1133, 1121, 1383, 1313, 1381, 1451, 1144,
        1380, 1146, 1012, 1212, 1417, 1018, 1085, 1287, 1239, 1032, 1191, 1217,
        1283, 1199, 1366, 1226, 1288, 1428, 1415, 1169, 1331, 1280, 1396, 1245,
        1596, 1280, 1146, 1361, 1268, 1253, 1551, 1302, 1338, 1246, 1431, 1130,
        1486, 1373, 1185, 1241, 1189, 1384, 1184, 1296, 1352, 1259, 1363, 1177,
        1050, 1180, 1210, 1436, 1114, 1256, 1632, 1461, 1415, 1322, 1474, 1415,
        1471, 1916, 1663, 1626, 1569, 1387, 1541, 1310, 1530, 1386, 1726, 1309,
        1341, 1427, 1481, 1333, 1438, 1519, 1468, 1545, 1523, 1466, 1426, 1619,
        1545, 1535, 1585, 1446, 1656, 1575, 1943, 1491, 1364, 1645, 1397, 1431,
        1841, 1485, 1650, 1508, 1649, 1436, 1559, 1813, 1608, 1347, 1557, 1641,
        1586, 1569, 1463, 1450, 1587, 1246, 1373, 1437, 1516, 1746, 1383, 1616,
        1719, 1645, 1450, 1405, 1522, 1454, 1419, 1883, 1583, 1691, 1617, 1492,
        1800, 1442, 1633, 1457, 1722, 1304, 1379, 1552, 1825, 1495, 1611, 1524,
        1519, 1485, 1752, 1437, 1532, 1630, 1553, 1544, 1653, 1736, 1781, 1452,
        1795, 1614, 1389, 1532, 1589, 1568, 2020, 1577, 1753, 1714, 1848, 1433,
        1722, 1693, 1430, 1602, 1618, 1739, 1640, 1563, 1544, 1501, 1522, 1388,
        1409, 1443, 1634, 1807, 1467, 1484, 1611, 1589, 1547, 1421, 1635, 1359,
        1402, 1797, 1567, 1662, 1769, 1438, 1587, 1414, 1611, 1496, 1788, 1359,
        1363, 1486, 1676, 1319, 1491, 1553, 1557, 1430, 1785, 1403, 1576, 1666,
        1585, 1495, 1540, 1595, 1742, 1432, 1890, 1444, 1354, 1781, 1362, 1530,
        1879, 1630, 1769, 1504, 1661, 1296, 1730, 1593, 1382, 1456, 1566, 1629,
        1566, 1626, 1519, 1559, 1449, 1407, 1258, 1467, 1503, 1766, 1416, 1372,
        1406, 1337, 1185, 1092, 1354, 1131, 1090, 1465, 1212, 1393, 1363, 1183,
        1386, 1217, 1246, 1043, 1421, 1150, 1052, 1209, 1351, 1155, 1181, 1267,
        1228, 1126, 1332, 1168, 1278, 1209, 1325, 1155, 1323, 1338, 1342, 1149,
        1574, 1166, 1163, 1313, 1215, 1266, 1658, 1260, 1380, 1296, 1346, 1250,
        1385, 1203, 1165, 1255, 1282, 1291, 1228, 1304, 1202, 1134, 1277, 1069,
        1009, 1166, 1271, 1434, 1057, 1104, 1301, 1347, 1176, 1160, 1377, 1129,
        1359, 1574, 1328, 1359, 1261, 1018, 1411, 1174, 1305, 1218, 1485, 1083,
        1120, 1398, 1329, 1168, 1258, 1314, 1389, 1347, 1352, 1224, 1391, 1404,
        1494, 1281, 1342, 1323, 1454, 1148, 1570, 1355, 1211, 1519, 1106, 1106,
        1605, 1237, 1521, 1431, 1500, 1200, 1494, 1460, 1194, 1169, 1304, 1362,
        1353, 1263, 1203, 1143, 1354, 1293, 1149, 1347, 1392, 1470, 1250, 1270,
        1505, 1545, 1340, 1220, 1514, 1245, 1442, 1607, 1501, 1546, 1570, 1300,
        1454, 1279, 1390, 1392, 1654, 1325, 1183, 1435, 1576, 1125, 1301, 1327,
        1337, 1381, 1455, 1303, 1410, 1497, 1569, 1474, 1412, 1591, 1595, 1312,
        1751, 1441, 1255, 1485, 1367, 1321, 1703, 1422, 1537, 1376, 1543, 1323,
        1657, 1503, 1385, 1307, 1384, 1494, 1471, 1495, 1454, 1313, 1436, 1347,
        1163, 1447, 1509, 1579, 1248, 1342, 1489, 1378, 1253, 1272, 1442, 1287,
        1278, 1624, 1429, 1389, 1398, 1172, 1462, 1345, 1301, 1217, 1510, 1282,
        1106, 1457, 1433, 1176, 1341, 1331, 1331, 1343, 1397, 1347, 1405, 1457,
        1459, 1389, 1471, 1406, 1566, 1489, 1645, 1404, 1204, 1511, 1294, 1417,
        1751, 1263, 1530, 1434, 1563, 1356, 1530, 1583, 1384, 1389, 1468, 1443,
        1278, 1315, 1451, 1237, 1422, 1206, 1191, 1331, 1358, 1641, 1187, 1236,
        1272, 1202, 1111, 1073, 1256, 943,  1118, 1375, 1158, 1163, 1271, 1059,
        1342, 1032, 1034, 1015, 1248, 1014, 969,  1202, 1144, 991,  1162, 1228,
        1217, 1029, 1290, 1125, 1158, 1129, 1188, 1146, 1292, 1183, 1315, 1054,
        1359, 1128, 901,  1336, 1102, 1160, 1476, 1138, 1284, 1212, 1441, 1017,
        1244, 1276, 1090, 1198, 1154, 1278, 1107, 1167, 1162, 951,  1171, 1062,
        1044, 1045, 1155, 1273, 1056, 1253, 1536, 1525, 1348, 1385, 1478, 1268,
        1375, 1726, 1509, 1669, 1621, 1462, 1534, 1350, 1497, 1311, 1606, 1205,
        1390, 1567, 1582, 1373, 1628, 1604, 1285, 1410, 1569, 1298, 1349, 1452,
        1515, 1627, 1557, 1517, 1667, 1411, 1847, 1610, 1296, 1620, 1490, 1511,
        1895, 1504, 1609, 1448, 1630, 1247, 1726, 1654, 1439, 1375, 1584, 1561,
        1569, 1634, 1442, 1329, 1621, 1432, 1246, 1413, 1500, 1752, 1393, 1406,
        1240, 1157, 1171, 1294, 1313, 1073, 1179, 1589, 1288, 1423, 1360, 1112,
        1350, 1178, 1357, 1113, 1422, 1147, 1118, 1353, 1242, 1059, 1270, 1228,
        1201, 1245, 1297, 1008, 1256, 1346, 1245, 1179, 1345, 1368, 1385, 1191,
        1517, 1296, 1145, 1336, 1273, 1191, 1502, 1384, 1391, 1262, 1523, 1224,
        1417, 1361, 1173, 972,  1294, 1239, 1282, 1329, 1195, 1104, 1351, 1162,
        1115, 1133, 1235, 1430, 1156, 1067, 1250, 1201, 1268, 1283, 1299, 1070,
        1086, 1462, 1265, 1336, 1417, 1296, 1300, 1233, 1302, 1236, 1427, 1185,
        1142, 1433, 1299, 1114, 1425, 1298, 1116, 1263, 1457, 1220, 1211, 1165,
        1303, 1307, 1263, 1221, 1380, 1134, 1596, 1255, 1248, 1396, 1298, 1255,
        1556, 1321, 1302, 1222, 1442, 1120, 1424, 1448, 1300, 1109, 1366, 1358,
        1339, 1408, 1270, 1225, 1403, 1122, 1072, 1253, 1169, 1420, 1233, 1154,
        1368, 1426, 1245, 1048, 1401, 1242, 1266, 1481, 1397, 1321, 1256, 1221,
        1433, 1103, 1123, 1238, 1465, 1067, 1243, 1320, 1220, 1097, 1172, 1234,
        1334, 1312, 1503, 1281, 1276, 1348, 1453, 1178, 1479, 1304, 1441, 1257,
        1602, 1284, 1166, 1415, 1283, 1277, 1613, 1311, 1495, 1455, 1409, 1056,
        1500, 1419, 1311, 1347, 1309, 1413, 1325, 1232, 1239, 1177, 1244, 1154,
        1129, 1286, 1262, 1394, 1245, 1139, 1707, 1657, 1377, 1465, 1391, 1324,
        1401, 1842, 1617, 1663, 1545, 1338, 1506, 1325, 1483, 1395, 1627, 1353,
        1336, 1422, 1585, 1300, 1451, 1407, 1435, 1416, 1544, 1432, 1506, 1646,
        1604, 1475, 1611, 1519, 1689, 1300, 1840, 1557, 1299, 1537, 1513, 1452,
        1859, 1569, 1827, 1640, 1769, 1358, 1543, 1728, 1411, 1316, 1479, 1572,
        1553, 1438, 1506, 1269, 1560, 1387, 1420, 1294, 1472, 1660, 1415, 1370,
        1492, 1410, 1263, 1313, 1665, 1278, 1329, 1687, 1492, 1574, 1431, 1245,
        1518, 1314, 1449, 1300, 1586, 1203, 1134, 1458, 1571, 1264, 1307, 1403,
        1494, 1402, 1546, 1279, 1434, 1504, 1590, 1362, 1458, 1481, 1734, 1388,
        1758, 1511, 1298, 1546, 1265, 1427, 1734, 1461, 1594, 1440, 1542, 1272,
        1520, 1660, 1308, 1293, 1431, 1508, 1523, 1487, 1499, 1330, 1447, 1320,
        1113, 1380, 1420, 1625, 1469, 1385, 1410, 1520, 1232, 1170, 1427, 1109,
        1281, 1567, 1371, 1503, 1385, 1274, 1453, 1228, 1350, 1230, 1557, 1212,
        1208, 1482, 1421, 1137, 1228, 1440, 1329, 1361, 1463, 1402, 1336, 1410,
        1456, 1391, 1366, 1475, 1673, 1258, 1577, 1436, 1195, 1546, 1275, 1346,
        1699, 1387, 1456, 1327, 1510, 1195, 1467, 1419, 1208, 1280, 1413, 1493,
        1463, 1540, 1445, 1251, 1335, 1187, 1071, 1364, 1387, 1599, 1273, 1263,
        1522, 1385, 1268, 1340, 1510, 1267, 1283, 1559, 1429, 1447, 1563, 1152,
        1455, 1100, 1255, 1308, 1508, 1304, 1175, 1278, 1372, 1083, 1236, 1424,
        1273, 1169, 1540, 1263, 1473, 1487, 1466, 1315, 1535, 1383, 1545, 1344,
        1636, 1303, 1225, 1402, 1262, 1322, 1717, 1223, 1510, 1482, 1598, 1234,
        1599, 1397, 1262, 1408, 1330, 1399, 1354, 1337, 1278, 1282, 1297, 1331,
        1092, 1186, 1297, 1409, 1264, 1330, 1232, 1201, 984,  1019, 1146, 996,
        963,  1329, 1181, 1239, 1177, 972,  1150, 1087, 1042, 1056, 1201, 1006,
        929,  1144, 1170, 1049, 1058, 1128, 1024, 1219, 1219, 1007, 1104, 1219,
        1149, 1097, 1197, 1311, 1254, 1061, 1378, 1164, 836,  1294, 1110, 1146,
        1510, 1129, 1325, 1160, 1190, 1000, 1327, 1143, 1033, 1101, 1103, 1214,
        1206, 1056, 1146, 998,  1111, 1002, 929,  987,  1226, 1343, 1015, 966,
        1361, 1307, 1148, 1274, 1428, 1312, 1165, 1505, 1407, 1348, 1288, 1118,
        1335, 1191, 1258, 1232, 1487, 1072, 1174, 1287, 1389, 1219, 1257, 1296,
        1311, 1343, 1396, 1261, 1258, 1489, 1249, 1410, 1405, 1150, 1504, 1331,
        1612, 1316, 1050, 1450, 1231, 1326, 1589, 1251, 1512, 1411, 1482, 1198,
        1433, 1429, 1249, 1337, 1218, 1426, 1365, 1257, 1296, 1219, 1299, 1203,
        1103, 1207, 1410, 1473, 1257, 1278, 1234, 1158, 1162, 984,  1187, 1163,
        1142, 1360, 1207, 1173, 1058, 1164, 1287, 927,  1099, 1142, 1279, 1023,
        1036, 1177, 1197, 1067, 1135, 1255, 1183, 1159, 1151, 1012, 1097, 1124,
        1157, 1130, 1189, 1230, 1232, 1233, 1442, 1113, 992,  1331, 1178, 1195,
        1454, 1201, 1348, 1138, 1298, 992,  1154, 1209, 1066, 1188, 1305, 1215,
        1188, 1221, 1104, 1053, 1191, 1002, 968,  1131, 1140, 1302, 1052, 1055,
        1579, 1537, 1246, 1301, 1496, 1260, 1336, 1718, 1460, 1499, 1491, 1246,
        1512, 1275, 1439, 1351, 1648, 1175, 1188, 1337, 1471, 1236, 1371, 1454,
        1359, 1368, 1394, 1346, 1493, 1608, 1488, 1526, 1476, 1547, 1576, 1289,
        1795, 1563, 1278, 1619, 1290, 1455, 1834, 1285, 1598, 1462, 1533, 1292,
        1649, 1571, 1284, 1440, 1353, 1424, 1636, 1414, 1432, 1337, 1446, 1345,
        1230, 1322, 1538, 1550, 1210, 1393, 1463, 1526, 1243, 1299, 1427, 1263,
        1319, 1546, 1461, 1499, 1497, 1269, 1379, 1281, 1331, 1223, 1534, 1171,
        1248, 1352, 1486, 1169, 1395, 1347, 1247, 1324, 1472, 1367, 1384, 1425,
        1496, 1567, 1531, 1475, 1484, 1288, 1716, 1412, 1208, 1424, 1239, 1289,
        1703, 1298, 1482, 1542, 1553, 1273, 1643, 1560, 1259, 1406, 1347, 1607,
        1532, 1294, 1294, 1212, 1447, 1322, 1250, 1340, 1445, 1578, 1303, 1296,
        1555, 1566, 1232, 1283, 1518, 1393, 1293, 1631, 1575, 1520, 1523, 1184,
        1416, 1279, 1344, 1293, 1574, 1270, 1229, 1286, 1449, 1368, 1471, 1482,
        1449, 1443, 1552, 1430, 1420, 1368, 1455, 1511, 1476, 1268, 1685, 1437,
        1921, 1412, 1299, 1643, 1257, 1430, 1818, 1447, 1685, 1381, 1608, 1158,
        1562, 1625, 1354, 1363, 1320, 1504, 1482, 1507, 1359, 1260, 1560, 1369,
        1225, 1434, 1425, 1659, 1419, 1419, 1531, 1696, 1102, 1243, 1486, 1364,
        1261, 1619, 1443, 1455, 1517, 1151, 1503, 1255, 1215, 1286, 1515, 1283,
        1136, 1332, 1478, 1104, 1301, 1333, 1390, 1355, 1434, 1335, 1396, 1486,
        1485, 1231, 1476, 1414, 1738, 1286, 1749, 1386, 1224, 1433, 1375, 1349,
        1649, 1449, 1520, 1401, 1656, 1209, 1498, 1343, 1317, 1336, 1263, 1528,
        1376, 1468, 1399, 1337, 1427, 1354, 1205, 1263, 1390, 1507, 1324, 1346,
        1366, 1368, 1219, 1130, 1323, 1177, 1246, 1517, 1321, 1418, 1329, 1211,
        1279, 1151, 1384, 1083, 1433, 1181, 1126, 1336, 1451, 1116, 1312, 1242,
        1306, 1255, 1264, 1142, 1303, 1344, 1346, 1160, 1334, 1351, 1458, 1305,
        1604, 1304, 1164, 1377, 1258, 1199, 1555, 1351, 1427, 1311, 1388, 1140,
        1359, 1326, 1176, 1116, 1304, 1309, 1432, 1466, 1236, 1194, 1362, 1096,
        1196, 1276, 1203, 1529, 1063, 1233, 1412, 1333, 1315, 1207, 1375, 1122,
        1180, 1513, 1390, 1444, 1399, 1305, 1355, 1109, 1248, 1330, 1534, 1252,
        1190, 1368, 1317, 1090, 1336, 1314, 1246, 1181, 1440, 1177, 1324, 1375,
        1347, 1255, 1365, 1412, 1473, 1271, 1590, 1248, 1194, 1526, 1368, 1279,
        1705, 1348, 1472, 1277, 1476, 1153, 1481, 1412, 1320, 1215, 1227, 1384,
        1251, 1251, 1242, 1229, 1497, 1190, 1134, 1347, 1318, 1524, 1238, 1294,
        1437, 1465, 1218, 1282, 1365, 1284, 1280, 1539, 1428, 1407, 1296, 1229,
        1463, 1299, 1215, 1230, 1509, 1138, 1244, 1448, 1432, 1125, 1389, 1249,
        1351, 1250, 1424, 1177, 1318, 1447, 1283, 1307, 1461, 1400, 1494, 1221,
        1643, 1325, 1123, 1467, 1290, 1322, 1627, 1380, 1476, 1307, 1565, 1210,
        1401, 1396, 1286, 1246, 1317, 1374, 1363, 1357, 1284, 1163, 1432, 1145,
        1215, 1406, 1461, 1522, 1199, 1286, 1266, 1313, 1081, 1091, 1227, 1095,
        1082, 1344, 1166, 1319, 1199, 1105, 1274, 1183, 1232, 1097, 1437, 1075,
        1039, 1225, 1245, 1038, 1117, 1212, 1236, 1148, 1352, 1136, 1265, 1296,
        1282, 1183, 1152, 1325, 1395, 1119, 1471, 1202, 1132, 1296, 1170, 1209,
        1496, 1208, 1306, 1151, 1417, 1165, 1274, 1249, 998,  1132, 1150, 1326,
        1201, 1348, 1186, 1155, 1250, 1129, 1044, 1185, 1204, 1450, 1142, 1174,
        1708, 1579, 1418, 1431, 1637, 1474, 1386, 1708, 1633, 1650, 1654, 1333,
        1540, 1327, 1383, 1312, 1789, 1259, 1333, 1449, 1590, 1277, 1367, 1499,
        1490, 1379, 1642, 1351, 1473, 1700, 1496, 1524, 1631, 1453, 1683, 1451,
        1699, 1543, 1288, 1647, 1415, 1455, 1704, 1494, 1672, 1532, 1664, 1409,
        1554, 1592, 1340, 1373, 1481, 1706, 1544, 1521, 1514, 1439, 1579, 1368,
        1332, 1494, 1468, 1620, 1355, 1405, 1692, 1700, 1486, 1480, 1806, 1522,
        1557, 1823, 1703, 1790, 1883, 1414, 1765, 1355, 1531, 1542, 1806, 1318,
        1570, 1560, 1795, 1430, 1576, 1619, 1663, 1551, 1613, 1422, 1530, 1734,
        1738, 1571, 1743, 1592, 1891, 1502, 1942, 1586, 1521, 1624, 1463, 1502,
        1952, 1580, 1751, 1784, 1820, 1606, 1829, 1805, 1601, 1425, 1716, 1821,
        1640, 1581, 1562, 1546, 1563, 1641, 1328, 1494, 1700, 1806, 1567, 1569,
        1447, 1238, 1155, 1199, 1268, 1088, 1217, 1544, 1316, 1332, 1333, 1164,
        1339, 1135, 1184, 1154, 1342, 1146, 1156, 1226, 1242, 1085, 1201, 1226,
        1192, 1252, 1302, 1121, 1303, 1295, 1380, 1249, 1291, 1232, 1395, 1161,
        1563, 1369, 1117, 1195, 1288, 1256, 1551, 1153, 1506, 1254, 1555, 1219,
        1320, 1408, 1265, 1034, 1219, 1345, 1255, 1242, 1200, 1096, 1412, 1127,
        1209, 1253, 1339, 1436, 1226, 1177, 1449, 1488, 1239, 1163, 1459, 1295,
        1434, 1414, 1402, 1489, 1337, 1173, 1321, 1226, 1360, 1292, 1522, 1112,
        1288, 1372, 1330, 1216, 1324, 1272, 1371, 1398, 1436, 1276, 1260, 1459,
        1530, 1236, 1491, 1399, 1588, 1221, 1686, 1401, 1257, 1407, 1130, 1322,
        1580, 1292, 1491, 1409, 1470, 1201, 1534, 1527, 1281, 1287, 1376, 1490,
        1402, 1442, 1272, 1255, 1311, 1409, 1143, 1352, 1431, 1555, 1234, 1191,
        1341, 1206, 1169, 1179, 1426, 1222, 1235, 1566, 1237, 1410, 1442, 1143,
        1339, 1115, 1274, 1323, 1555, 1135, 1102, 1279, 1277, 1113, 1267, 1226,
        1243, 1276, 1297, 1188, 1203, 1373, 1252, 1263, 1323, 1333, 1398, 1284,
        1662, 1244, 1115, 1416, 1191, 1322, 1535, 1319, 1415, 1155, 1415, 1267,
        1371, 1429, 1189, 1224, 1212, 1377, 1378, 1334, 1331, 1271, 1235, 1187,
        1064, 1171, 1333, 1473, 1134, 1220, 1592, 1529, 1386, 1437, 1543, 1418,
        1423, 1742, 1590, 1687, 1604, 1302, 1567, 1287, 1299, 1281, 1536, 1403,
        1353, 1352, 1502, 1325, 1422, 1499, 1447, 1350, 1647, 1499, 1578, 1529,
        1581, 1429, 1600, 1461, 1599, 1519, 1728, 1372, 1300, 1684, 1394, 1555,
        1914, 1459, 1677, 1555, 1644, 1115, 1657, 1588, 1263, 1475, 1417, 1547,
        1309, 1357, 1379, 1428, 1466, 1383, 1189, 1446, 1399, 1601, 1362, 1292,
        1243, 1332, 1139, 1040, 1241, 1272, 1185, 1448, 1242, 1319, 1317, 1027,
        1398, 1068, 1168, 1157, 1443, 942,  1070, 1196, 1218, 1161, 1217, 1127,
        1279, 1128, 1313, 1212, 1145, 1388, 1349, 1206, 1277, 1323, 1454, 1238,
        1656, 1206, 1063, 1342, 1165, 1187, 1459, 1255, 1448, 1219, 1453, 1120,
        1383, 1316, 1258, 1203, 1214, 1292, 1300, 1219, 1250, 1176, 1283, 1266,
        1012, 1167, 1228, 1390, 1104, 1080, 1470, 1543, 1305, 1416, 1610, 1364,
        1374, 1670, 1606, 1678, 1648, 1409, 1593, 1392, 1395, 1445, 1721, 1255,
        1479, 1643, 1629, 1384, 1537, 1521, 1502, 1499, 1546, 1373, 1536, 1714,
        1550, 1528, 1584, 1494, 1729, 1532, 1746, 1698, 1435, 1656, 1511, 1556,
        1842, 1476, 1681, 1523, 1729, 1313, 1658, 1629, 1486, 1329, 1611, 1682,
        1546, 1539, 1543, 1401, 1497, 1395, 1289, 1419, 1530, 1754, 1438, 1507,
        1497, 1526, 1234, 1248, 1584, 1325, 1324, 1619, 1346, 1517, 1615, 1066,
        1484, 1226, 1263, 1220, 1529, 1252, 1106, 1380, 1432, 1038, 1318, 1453,
        1424, 1348, 1527, 1373, 1444, 1498, 1440, 1401, 1495, 1456, 1565, 1394,
        1617, 1386, 1207, 1602, 1272, 1291, 1664, 1363, 1476, 1329, 1545, 1301,
        1480, 1300, 1084, 1281, 1342, 1481, 1473, 1423, 1385, 1349, 1426, 1303,
        1166, 1293, 1393, 1520, 1253, 1365, 1679, 1597, 1419, 1337, 1438, 1364,
        1396, 1821, 1586, 1580, 1537, 1285, 1580, 1269, 1246, 1364, 1607, 1272,
        1351, 1503, 1378, 1211, 1363, 1419, 1447, 1383, 1556, 1393, 1467, 1652,
        1626, 1461, 1487, 1555, 1600, 1402, 1798, 1397, 1191, 1467, 1488, 1423,
        1715, 1407, 1730, 1639, 1720, 1395, 1584, 1628, 1438, 1493, 1380, 1516,
        1384, 1385, 1454, 1433, 1489, 1295, 1279, 1375, 1481, 1587, 1311, 1414,
        1316, 1458, 1177, 1206, 1404, 1185, 1172, 1516, 1389, 1400, 1466, 1256,
        1398, 1235, 1235, 1363, 1604, 1178, 1142, 1250, 1410, 1141, 1289, 1417,
        1268, 1381, 1399, 1276, 1308, 1426, 1502, 1389, 1282, 1317, 1560, 1305,
        1742, 1300, 1216, 1397, 1255, 1352, 1747, 1263, 1471, 1287, 1396, 1297,
        1534, 1502, 1306, 1252, 1380, 1464, 1356, 1397, 1359, 1291, 1445, 1183,
        1164, 1281, 1375, 1472, 1217, 1327
      ]);
    });

    it('A x B vec4', async () => {
      const a = tf.tensor3d(
          [
            2, 1, 3,  2,  1, 1, 1, 5,  6,  7, 8, 1, 2,  2,  1, 9, 11, 10, 1,
            1, 3, 2,  1,  1, 2, 1, 3,  2,  1, 1, 1, 5,  6,  7, 8, 1,  2,  2,
            1, 9, 11, 10, 1, 1, 3, 2,  1,  1, 2, 1, 3,  2,  1, 1, 1,  5,  6,
            7, 8, 1,  2,  2, 1, 9, 11, 10, 1, 1, 3, 2,  1,  1, 2, 1,  3,  2,
            1, 1, 1,  5,  6, 7, 8, 1,  2,  2, 1, 9, 11, 10, 1, 1, 3,  2,  1,
            1, 2, 1,  3,  2, 1, 1, 1,  5,  6, 7, 8, 1,  2,  2, 1, 9,  11, 10,
            1, 1, 3,  2,  1, 1, 2, 1,  3,  2, 1, 1, 1,  5
          ],
          [1, 32, 4]);

      const b = tf.tensor3d(
          [
            2, 1, 3,  2,  1, 1, 1, 5,  6,  7, 8, 1, 2,  2,  1, 9, 11, 10, 1,
            1, 3, 2,  1,  1, 2, 1, 3,  2,  1, 1, 1, 5,  6,  7, 8, 1,  2,  2,
            1, 9, 11, 10, 1, 1, 3, 2,  1,  1, 2, 1, 3,  2,  1, 1, 1,  5,  6,
            7, 8, 1,  2,  2, 1, 9, 11, 10, 1, 1, 3, 2,  1,  1, 2, 1,  3,  2,
            1, 1, 1,  5,  6, 7, 8, 1,  2,  2, 1, 9, 11, 10, 1, 1, 3,  2,  1,
            1, 2, 1,  3,  2, 1, 1, 1,  5,  6, 7, 8, 1,  2,  2, 1, 9,  11, 10,
            1, 1, 3,  2,  1, 1, 2, 1,  3,  2, 1, 1, 1,  5
          ],
          [1, 4, 32]);
      const c = tf.matMul(a, b);
      expect(c.shape).toEqual([1, 32, 32]);
      test_util.expectArraysClose(await c.data(), [
        47,  41,  23,  12, 15, 12, 8,  32,  41,  41,  42,  11, 14, 13, 8,  52,
        64,  62,  31,  9,  19, 15, 8,  36,  47,  41,  23,  12, 15, 12, 8,  32,
        29,  23,  27,  14, 11, 10, 8,  40,  49,  53,  52,  9,  16, 15, 8,  60,
        74,  68,  17,  9,  21, 15, 8,  20,  29,  23,  27,  14, 11, 10, 8,  40,
        144, 136, 85,  29, 45, 37, 22, 106, 135, 127, 87,  30, 43, 36, 22, 110,
        139, 133, 92,  29, 44, 37, 22, 114, 144, 136, 85,  29, 45, 37, 22, 106,
        45,  35,  50,  25, 18, 17, 14, 74,  90,  98,  93,  15, 29, 27, 14, 106,
        131, 119, 25,  16, 37, 26, 14, 30,  45,  35,  50,  25, 18, 17, 14, 74,
        95,  92,  117, 35, 35, 34, 23, 151, 184, 185, 109, 24, 55, 45, 23, 123,
        158, 137, 50,  33, 48, 36, 23, 71,  95,  92,  117, 35, 35, 34, 23, 151,
        31,  28,  29,  11, 11, 10, 7,  39,  48,  49,  37,  8,  15, 13, 7,  43,
        54,  49,  18,  9,  16, 12, 7,  23,  31,  28,  29,  11, 11, 10, 7,  39,
        47,  41,  23,  12, 15, 12, 8,  32,  41,  41,  42,  11, 14, 13, 8,  52,
        64,  62,  31,  9,  19, 15, 8,  36,  47,  41,  23,  12, 15, 12, 8,  32,
        29,  23,  27,  14, 11, 10, 8,  40,  49,  53,  52,  9,  16, 15, 8,  60,
        74,  68,  17,  9,  21, 15, 8,  20,  29,  23,  27,  14, 11, 10, 8,  40,
        144, 136, 85,  29, 45, 37, 22, 106, 135, 127, 87,  30, 43, 36, 22, 110,
        139, 133, 92,  29, 44, 37, 22, 114, 144, 136, 85,  29, 45, 37, 22, 106,
        45,  35,  50,  25, 18, 17, 14, 74,  90,  98,  93,  15, 29, 27, 14, 106,
        131, 119, 25,  16, 37, 26, 14, 30,  45,  35,  50,  25, 18, 17, 14, 74,
        95,  92,  117, 35, 35, 34, 23, 151, 184, 185, 109, 24, 55, 45, 23, 123,
        158, 137, 50,  33, 48, 36, 23, 71,  95,  92,  117, 35, 35, 34, 23, 151,
        31,  28,  29,  11, 11, 10, 7,  39,  48,  49,  37,  8,  15, 13, 7,  43,
        54,  49,  18,  9,  16, 12, 7,  23,  31,  28,  29,  11, 11, 10, 7,  39,
        47,  41,  23,  12, 15, 12, 8,  32,  41,  41,  42,  11, 14, 13, 8,  52,
        64,  62,  31,  9,  19, 15, 8,  36,  47,  41,  23,  12, 15, 12, 8,  32,
        29,  23,  27,  14, 11, 10, 8,  40,  49,  53,  52,  9,  16, 15, 8,  60,
        74,  68,  17,  9,  21, 15, 8,  20,  29,  23,  27,  14, 11, 10, 8,  40,
        144, 136, 85,  29, 45, 37, 22, 106, 135, 127, 87,  30, 43, 36, 22, 110,
        139, 133, 92,  29, 44, 37, 22, 114, 144, 136, 85,  29, 45, 37, 22, 106,
        45,  35,  50,  25, 18, 17, 14, 74,  90,  98,  93,  15, 29, 27, 14, 106,
        131, 119, 25,  16, 37, 26, 14, 30,  45,  35,  50,  25, 18, 17, 14, 74,
        95,  92,  117, 35, 35, 34, 23, 151, 184, 185, 109, 24, 55, 45, 23, 123,
        158, 137, 50,  33, 48, 36, 23, 71,  95,  92,  117, 35, 35, 34, 23, 151,
        31,  28,  29,  11, 11, 10, 7,  39,  48,  49,  37,  8,  15, 13, 7,  43,
        54,  49,  18,  9,  16, 12, 7,  23,  31,  28,  29,  11, 11, 10, 7,  39,
        47,  41,  23,  12, 15, 12, 8,  32,  41,  41,  42,  11, 14, 13, 8,  52,
        64,  62,  31,  9,  19, 15, 8,  36,  47,  41,  23,  12, 15, 12, 8,  32,
        29,  23,  27,  14, 11, 10, 8,  40,  49,  53,  52,  9,  16, 15, 8,  60,
        74,  68,  17,  9,  21, 15, 8,  20,  29,  23,  27,  14, 11, 10, 8,  40,
        144, 136, 85,  29, 45, 37, 22, 106, 135, 127, 87,  30, 43, 36, 22, 110,
        139, 133, 92,  29, 44, 37, 22, 114, 144, 136, 85,  29, 45, 37, 22, 106,
        45,  35,  50,  25, 18, 17, 14, 74,  90,  98,  93,  15, 29, 27, 14, 106,
        131, 119, 25,  16, 37, 26, 14, 30,  45,  35,  50,  25, 18, 17, 14, 74,
        95,  92,  117, 35, 35, 34, 23, 151, 184, 185, 109, 24, 55, 45, 23, 123,
        158, 137, 50,  33, 48, 36, 23, 71,  95,  92,  117, 35, 35, 34, 23, 151,
        31,  28,  29,  11, 11, 10, 7,  39,  48,  49,  37,  8,  15, 13, 7,  43,
        54,  49,  18,  9,  16, 12, 7,  23,  31,  28,  29,  11, 11, 10, 7,  39,
        47,  41,  23,  12, 15, 12, 8,  32,  41,  41,  42,  11, 14, 13, 8,  52,
        64,  62,  31,  9,  19, 15, 8,  36,  47,  41,  23,  12, 15, 12, 8,  32,
        29,  23,  27,  14, 11, 10, 8,  40,  49,  53,  52,  9,  16, 15, 8,  60,
        74,  68,  17,  9,  21, 15, 8,  20,  29,  23,  27,  14, 11, 10, 8,  40,
        144, 136, 85,  29, 45, 37, 22, 106, 135, 127, 87,  30, 43, 36, 22, 110,
        139, 133, 92,  29, 44, 37, 22, 114, 144, 136, 85,  29, 45, 37, 22, 106,
        45,  35,  50,  25, 18, 17, 14, 74,  90,  98,  93,  15, 29, 27, 14, 106,
        131, 119, 25,  16, 37, 26, 14, 30,  45,  35,  50,  25, 18, 17, 14, 74,
        95,  92,  117, 35, 35, 34, 23, 151, 184, 185, 109, 24, 55, 45, 23, 123,
        158, 137, 50,  33, 48, 36, 23, 71,  95,  92,  117, 35, 35, 34, 23, 151,
        31,  28,  29,  11, 11, 10, 7,  39,  48,  49,  37,  8,  15, 13, 7,  43,
        54,  49,  18,  9,  16, 12, 7,  23,  31,  28,  29,  11, 11, 10, 7,  39,
        47,  41,  23,  12, 15, 12, 8,  32,  41,  41,  42,  11, 14, 13, 8,  52,
        64,  62,  31,  9,  19, 15, 8,  36,  47,  41,  23,  12, 15, 12, 8,  32,
        29,  23,  27,  14, 11, 10, 8,  40,  49,  53,  52,  9,  16, 15, 8,  60,
        74,  68,  17,  9,  21, 15, 8,  20,  29,  23,  27,  14, 11, 10, 8,  40
      ]);
    });

    it('A x B vec4 A is a vector', async () => {
      const a = tf.tensor3d([2, 1, 3, 2], [1, 1, 4]);

      const b = tf.tensor3d(
          [
            2, 1, 3,  2,  1, 1, 1, 5,  6,  7, 8, 1, 2,  2,  1, 9, 11, 10, 1,
            1, 3, 2,  1,  1, 2, 1, 3,  2,  1, 1, 1, 5,  6,  7, 8, 1,  2,  2,
            1, 9, 11, 10, 1, 1, 3, 2,  1,  1, 2, 1, 3,  2,  1, 1, 1,  5,  6,
            7, 8, 1,  2,  2, 1, 9, 11, 10, 1, 1, 3, 2,  1,  1, 2, 1,  3,  2,
            1, 1, 1,  5,  6, 7, 8, 1,  2,  2, 1, 9, 11, 10, 1, 1, 3,  2,  1,
            1, 2, 1,  3,  2, 1, 1, 1,  5,  6, 7, 8, 1,  2,  2, 1, 9,  11, 10,
            1, 1, 3,  2,  1, 1, 2, 1,  3,  2, 1, 1, 1,  5
          ],
          [1, 4, 32]);
      const c = tf.matMul(a, b);
      expect(c.shape).toEqual([1, 1, 32]);
      test_util.expectArraysClose(await c.data(), [
        47, 41, 23, 12, 15, 12, 8, 32, 41, 41, 42, 11, 14, 13, 8, 52,
        64, 62, 31, 9,  19, 15, 8, 36, 47, 41, 23, 12, 15, 12, 8, 32
      ]);
    });

    it('A^t x B vec4', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
      const b = tf.tensor2d([1, 0, 2, 4, 3, 0, 5, 6], [2, 4]);

      const transposeA = true;
      const transposeB = false;
      const c = tf.matMul(a, b, transposeA, transposeB);
      const result = await c.data();
      const expected =
          [16, 0, 27, 34, 20, 0, 34, 44, 24, 0, 41, 54, 28, 0, 48, 64];
      test_util.expectArraysClose(result, expected);
    });

    it('fused A x B vec4 with relu', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
      const b = tf.tensor2d(
          [0, 1, -3, 2, 2, 1, 1, 0, 2, 4, 3, 0, 5, -6, 7, -8], [4, 4]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'relu'});

      expect(c.shape).toEqual([2, 4]);
      expectArraysClose(await c.data(), [30, 0, 36, 0, 66, 0, 68, 0]);
    });

    it('fused A x B vec4 with elu', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
      const b = tf.tensor2d(
          [0, 1, -3, 2, 2, 1, 1, 0, 2, 4, 3, 0, 5, -6, 7, -8], [4, 4]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'elu'});

      expect(c.shape).toEqual([2, 4]);
      expectArraysClose(
          await c.data(), [30, -0.9999, 36, -1, 66, -0.9999, 68, -1]);
    });

    it('fused A x B vec4 with relu6', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
      const b = tf.tensor2d(
          [0, 1, -3, 2, 2, 1, 1, 0, 2, 4, 3, 0, 5, -6, 7, -8], [4, 4]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'relu6'});

      expect(c.shape).toEqual([2, 4]);
      expectArraysClose(await c.data(), [6, 0, 6, 0, 6, 0, 6, 0]);
    });

    it('fused A x B vec4 with prelu', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
      const b = tf.tensor2d(
          [0, 1, -3, 2, 2, 1, 1, 0, 2, 4, 3, 0, 5, -6, 7, -8], [4, 4]);
      const alpha = tf.tensor2d([0.5, 0.5, 0.5, 0.5], [1, 4]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul({
        a,
        b,
        transposeA,
        transposeB,
        bias: null,
        activation: 'prelu',
        preluActivationWeights: alpha
      });

      expect(c.shape).toEqual([2, 4]);
      expectArraysClose(await c.data(), [30, -4.5, 36, -15, 66, -4.5, 68, -27]);
    });

    it('fused A x B vec4 with leakyrelu', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
      const b = tf.tensor2d(
          [0, 1, -3, 2, 2, 1, 1, 0, 2, 4, 3, 0, 5, -6, 7, -8], [4, 4]);
      const alpha = 0.3;
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul({
        a,
        b,
        transposeA,
        transposeB,
        bias: null,
        activation: 'leakyrelu',
        leakyreluAlpha: alpha
      });

      expect(c.shape).toEqual([2, 4]);
      expectArraysClose(await c.data(), [
        30, -2.700000047683716, 36, -9, 66, -2.700000047683716, 68,
        -16.200000762939453
      ]);
    });

    it('fused A x B vec4 with leakyrelu not provided.', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
      const b = tf.tensor2d(
          [0, 1, -3, 2, 2, 1, 1, 0, 2, 4, 3, 0, 5, -6, 7, -8], [4, 4]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'leakyrelu'});

      expect(c.shape).toEqual([2, 4]);
      // leakyRelu should use default alpha=0.2.
      expectArraysClose(await c.data(), [
        30, -1.8000000715255737, 36, -6, 66, -1.8000000715255737, 68,
        -10.800000190734863
      ]);
    });

    it('fused A x B with sigmoid', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
      const b = tf.tensor2d(
          [0, 1, -3, 2, 2, 1, 1, 0, 2, 4, 3, 0, 5, -6, 7, -8], [4, 4]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'sigmoid'});

      expect(c.shape).toEqual([2, 4]);
      expectArraysClose(await c.data(), [
        1, 0.00012339462409727275, 1, 9.35763443186792e-14, 1,
        0.00012339462409727275, 1, 3.5326268130932535e-24
      ]);
    });

    it('fused A x B vec4 with 2d bias and relu', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
      const b = tf.tensor2d(
          [0, 1, -3, 2, 2, 1, 1, 0, 2, 4, 3, 0, 5, -6, 7, -8], [4, 4]);
      const c = tf.tensor2d([1, 1, 1, 1, 1, 1, 1, 1], [2, 4]);
      const transposeA = false;
      const transposeB = false;

      const d = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: c, activation: 'relu'});

      expect(d.shape).toEqual([2, 4]);
      expectArraysClose(await d.data(), [31, 0, 37, 0, 67, 0, 69, 0]);
    });

    it('fused A x B vec4 with relu and broadcasted bias', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6, 7, 8], [2, 4]);
      const b = tf.tensor2d(
          [0, 1, -3, 2, 2, 1, 1, 0, 2, 4, 3, 0, 5, -6, 7, -8], [4, 4]);
      const c = tf.tensor1d([1, 1, 1, 1]);
      const act: tf.fused.Activation = 'relu';
      const transposeA = false;
      const transposeB = false;

      const d = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: c, activation: act});

      expect(d.shape).toEqual([2, 4]);
      expectArraysClose(await d.data(), [31, 0, 37, 0, 67, 0, 69, 0]);
    });

    // Below cases are from mat_mul_test.ts in tfjs-core.
    it('A x B', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);

      const c = tf.matMul(a, b);

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0, 8, -3, 20]);
    });

    it('A x B with M/N/K divisible by 4. [8,4]x[4,8]', async () => {
      const a = tf.tensor2d(
          [
            1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
            17, 18, 19, 20, 21, 22, 23, 24, 1, 2,  3,  4,  5,  6,  7,  8
          ],
          [8, 4]);
      const b = tf.tensor2d(
          [
            0,  1,  -3, 2, 1,  -1, 0, 5,  6, 7, 8, 0, -2, -2, 1, 9,
            11, 10, 0,  1, -3, 2,  1, -1, 1, 2, 3, 4, 5,  6,  7, 8
          ],
          [4, 8]);

      const c = tf.matMul(a, b);
      const cData = await c.data();

      expect(c.shape).toEqual([8, 8]);
      expectArraysClose(cData, [
        49,  53,  25,  21,  8,   25,  33,  52,  121, 133, 57,  49,  12,
        45,  69,  136, 193, 213, 89,  77,  16,  65,  105, 220, 265, 293,
        121, 105, 20,  85,  141, 304, 337, 373, 153, 133, 24,  105, 177,
        388, 409, 453, 185, 161, 28,  125, 213, 472, 49,  53,  25,  21,
        8,   25,  33,  52,  121, 133, 57,  49,  12,  45,  69,  136
      ]);
    });

    it('A x B with large K. [16,2048]x[2048,16]', async () => {
      const a = tf.tensor2d(new Array(16 * 2048).fill(1), [16, 2048]);
      const b = tf.tensor2d(new Array(2048 * 16).fill(1), [2048, 16]);

      const c = tf.matMul(a, b);
      const cData = await c.data();

      expect(c.shape).toEqual([16, 16]);
      expectArraysClose(cData, new Array(16 * 16).fill(2048));
    });

    it('matmul followed by mul', async () => {
      const a = tf.tensor2d([1, 2, 3, 4], [2, 2]);
      const b = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);

      const c = tf.matMul(a, b);

      const f = tf.tensor2d([0, 1, 0.5, 0, 0.25, 2], [2, 3]);
      const d = tf.mul(c, f);

      const dData = await d.data();

      expect(d.shape).toEqual([2, 3]);
      expectArraysClose(dData, [0, 12, 7.5, 0, 6.5, 66]);
    });

    it('A x B^t', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([1, 0, 2, 4, 3, 0], [2, 3]);

      const transposeA = false;
      const transposeB = true;
      const c = tf.matMul(a, b, transposeA, transposeB);

      const expected = [7, 10, 16, 31];
      expectArraysClose(await c.data(), expected);
    });

    it('A^t x B', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([1, 0, 2, 4, 3, 0], [2, 3]);

      const transposeA = true;
      const transposeB = false;
      const c = tf.matMul(a, b, transposeA, transposeB);

      const expected = [17, 12, 2, 22, 15, 4, 27, 18, 6];
      expectArraysClose(await c.data(), expected);
    });

    it('A^t x B^t', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [3, 2]);
      const b = tf.tensor2d([1, 0, 2, 4, 3, 0], [2, 3]);

      const transposeA = true;
      const transposeB = true;
      const c = tf.matMul(a, b, transposeA, transposeB);

      const expected = [11, 13, 14, 20];
      expectArraysClose(await c.data(), expected);
    });

    it('Vector times matrix', async () => {
      const v = tf.tensor1d([2, 3]);
      const matrix = tf.tensor2d([1, 2, 3, 4], [2, 2]);
      const result = tf.dot(v, matrix);

      const expected = [11, 16];
      expectArraysClose(await result.data(), expected);
    });

    it('Vector times matrix with implicit reshape', async () => {
      const v = tf.tensor1d([2, 3]);

      const matrix = tf.tensor2d([1, 2, 3, 4], [2, 2]);
      const result = tf.dot(v, matrix);

      const expected = [11, 16];
      expectArraysClose(await result.data(), expected);
    });

    it('Matrix times vector', async () => {
      const matrix = tf.tensor2d([1, 2, 3, 4], [2, 2]);
      const v = tf.tensor1d([2, 3]);
      const result = tf.dot(matrix, v);

      const expected = [8, 18];
      expectArraysClose(await result.data(), expected);
    });

    it('accepts a tensor-like object', async () => {
      const a = [[1, 2, 3], [4, 5, 6]];     // 2x3
      const b = [[0, 1], [-3, 2], [2, 1]];  // 3x2
      const c = tf.matMul(a, b);

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0, 8, -3, 20]);
    });

    it('accepts a tensor-like object chained', async () => {
      const a = tf.tensor2d([[1, 2, 3], [4, 5, 6]], [2, 3]);  // 2x3
      const b = [[0, 1], [-3, 2], [2, 1]];                    // 3x2
      const c = a.matMul(b);

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0, 8, -3, 20]);
    });

    it('a * b where a has zero in its shape', async () => {
      const a = tf.tensor2d([], [0, 3]);
      const b = tf.tensor2d([1, 2, 3, 4, 5, 6], [3, 2]);
      const c = tf.matMul(a, b);
      expect(c.shape).toEqual([0, 2]);
      expect(c.rank).toBe(2);
      expect(c.size).toBe(0);
      expectArraysClose(await c.data(), []);
    });

    it('(a * b) * c where a has zero in its shape, so a*b does also',
       async () => {
         const a = tf.tensor2d([], [0, 3]);
         const b = tf.tensor2d([1, 2, 3, 4, 5, 6], [3, 2]);
         const ab = tf.matMul(a, b);
         expect(ab.shape).toEqual([0, 2]);
         expectArraysClose(await ab.data(), []);
         const c = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
         const res = tf.matMul(ab, c);
         expect(res.shape).toEqual([0, 3]);
         expectArraysClose(await res.data(), []);
       });

    it('fused A x B', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);

      const c = tf.fused.matMul({a, b});

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0, 8, -3, 20]);
    });

    it('fused A x B with relu', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'relu'});

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0, 8, 0, 20]);
    });

    it('fused A x B with elu', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'elu'});

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0, 8, -0.9502, 20]);
    });

    it('fused A x B with relu6', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'relu6'});

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0, 6, 0, 6]);
    });

    it('fused A x B with prelu', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const alpha = tf.tensor2d([0.5, 0.5], [1, 2]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul({
        a,
        b,
        transposeA,
        transposeB,
        bias: null,
        activation: 'prelu',
        preluActivationWeights: alpha
      });

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0, 8, -1.5, 20]);
    });

    it('fused A x B with leakyrelu', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const alpha = 0.3;
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul({
        a,
        b,
        transposeA,
        transposeB,
        bias: null,
        activation: 'leakyrelu',
        leakyreluAlpha: alpha
      });

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0, 8, -0.9000000357627869, 20]);
    });

    it('fused A x B with leakyrelu not provided.', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'leakyrelu'});

      expect(c.shape).toEqual([2, 2]);
      // leakyRelu should use default alpha=0.2.
      expectArraysClose(await c.data(), [0, 8, -0.6000000238418579, 20]);
    });

    it('fused A x B with sigmoid', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const transposeA = false;
      const transposeB = false;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'sigmoid'});

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0.5, 0.99966455, 0.04742587, 1]);
    });

    it('fused A x B with relu transpose', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [2, 3]);
      const transposeA = false;
      const transposeB = true;

      const c = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: null, activation: 'relu'});

      expect(c.shape).toEqual([2, 2]);
      expectArraysClose(await c.data(), [0, 9, 0, 24]);
    });

    it('fused A x B with 2d bias and relu', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const c = tf.tensor2d([1, 1, 1, 1], [2, 2]);
      const transposeA = false;
      const transposeB = false;

      const d = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: c, activation: 'relu'});

      expect(d.shape).toEqual([2, 2]);
      expectArraysClose(await d.data(), [1, 9, 0, 21]);
    });

    it('fused A x B with relu and broadcasted bias', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const c = tf.tensor1d([1, 1]);
      const act: tf.fused.Activation = 'relu';
      const transposeA = false;
      const transposeB = false;

      const d = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: c, activation: act});

      expect(d.shape).toEqual([2, 2]);
      expectArraysClose(await d.data(), [1, 9, 0, 21]);
    });

    it('fused A x B with elu and broadcasted bias', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const c = tf.tensor1d([1, 1]);
      const act: tf.fused.Activation = 'elu';
      const transposeA = false;
      const transposeB = false;

      const d = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: c, activation: act});

      expect(d.shape).toEqual([2, 2]);
      expectArraysClose(await d.data(), [1, 9, -0.8647, 21]);
    });

    it('fused A x B with elu and broadcasted shape', async () => {
      const a = tf.tensor3d([1, 2, 3, 4, 5, 6], [1, 2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const c = tf.tensor1d([1, 1]);
      const act: tf.fused.Activation = 'elu';
      const transposeA = false;
      const transposeB = false;

      const d = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: c, activation: act});

      expect(d.shape).toEqual([1, 2, 2]);
      expectArraysClose(await d.data(), [1, 9, -0.8647, 21]);
    });

    it('fused A x B with 2d bias only', async () => {
      const a = tf.tensor2d([1, 2, 3, 4, 5, 6], [2, 3]);
      const b = tf.tensor2d([0, 1, -3, 2, 2, 1], [3, 2]);
      const c = tf.tensor2d([1, 1, 1, 1], [2, 2]);
      const transposeA = false;
      const transposeB = false;

      const d = tf.fused.matMul(
          {a, b, transposeA, transposeB, bias: c, activation: 'linear'});

      expect(d.shape).toEqual([2, 2]);
      expectArraysClose(await d.data(), [1, 9, -2, 21]);
    });
  };
}

// Below cases are from [fused_]mat_mul_test.ts in tfjs-core.
function matmulBatchTest(programType: MatMulProgramType) {
  return () => {
    let savedMatmulFlag = -1;
    beforeAll(() => {
      savedMatmulFlag = tf.env().get('WEBGPU_MATMUL_PROGRAM_TYPE') as number;
      tf.env().set('WEBGPU_MATMUL_PROGRAM_TYPE', programType);
    });
    afterAll(() => {
      tf.env().set('WEBGPU_MATMUL_PROGRAM_TYPE', savedMatmulFlag);
    });

    it('fused A x B with relu and broadcasted bias different rank',
       async () => {
         const a =
             tf.tensor3d([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [2, 2, 3]);
         const b =
             tf.tensor3d([0, 1, -3, 2, 2, 1, 0, 1, -3, 2, 2, 1], [2, 3, 2]);
         const c = tf.tensor2d([1, 2], [1, 2]);
         const act: tf.fused.Activation = 'relu';
         const transposeA = false;
         const transposeB = false;

         const d = tf.fused.matMul(
             {a, b, transposeA, transposeB, bias: c, activation: act});

         expect(d.shape).toEqual([2, 2, 2]);
         expectArraysClose(await d.data(), [2, 6, 0, 18, 0, 30, 0, 42]);
       });

    it('broadcast with unequal batch dims', async () => {
      const a = tf.tensor3d(
          [
            2, 1, 3, 2, 1,  1,  1, 5, 6, 7, 8, 1,
            2, 2, 1, 9, 11, 10, 1, 1, 3, 2, 1, 1
          ],
          [4, 3, 2]);
      const b = tf.tensor3d([1, 0.5], [1, 2, 1]);
      const c = tf.matMul(a, b);
      expect(c.shape).toEqual([4, 3, 1]);
      expectArraysClose(
          await c.data(),
          [2.5, 4, 1.5, 3.5, 9.5, 8.5, 3, 5.5, 16, 1.5, 4, 1.5]);
    });

    it('broadcast with unequal ranks', async () => {
      const a = tf.tensor5d(
          [
            2, 1, 3, 2, 1,  1,  1, 5, 6, 7, 8, 1,
            2, 2, 1, 9, 11, 10, 1, 1, 3, 2, 1, 1
          ],
          [1, 2, 2, 3, 2]);
      const b = tf.tensor2d([1, 0.5], [2, 1]);
      const c = tf.matMul(a, b);
      expect(c.shape).toEqual([1, 2, 2, 3, 1]);
      expectArraysClose(
          await c.data(),
          [2.5, 4, 1.5, 3.5, 9.5, 8.5, 3, 5.5, 16, 1.5, 4, 1.5]);
    });

    it('batched matmul with the matrices being vectors', async () => {
      const batch = 3;
      const sharedDim = MATMUL_SHARED_DIM_THRESHOLD + 1;
      const values = new Float32Array(batch * sharedDim);
      values[10] = 2;

      const a = tf.tensor(values, [batch, 1, sharedDim]);
      const b = tf.tensor(values, [batch, sharedDim, 1]);
      const result = tf.matMul(a, b);
      expect(result.shape).toEqual([batch, 1, 1]);
      expectArraysClose(await result.data(), [4, 0, 0]);
    });

    it('batched matmul called twice so memory of output is reused',
       async () => {
         const batch = 3;
         const n = 2;
         const vals = new Float32Array(batch * n * n);
         vals[0] = 2;
         vals[4] = 3;
         vals[8] = 4;

         const a = tf.tensor(vals, [batch, n, n]);
         const b = tf.tensor(vals, [batch, n, n]);
         const result = tf.matMul(a, b);
         expect(result.shape).toEqual([batch, n, n]);
         expectArraysClose(
             await result.data(), [4, 0, 0, 0, 9, 0, 0, 0, 16, 0, 0, 0]);
         // Dispose the first output, so memory of the second output (which has
         // the same shape), could be reused.
         result.dispose();

         const vals2 = new Float32Array(batch * n * n);
         vals2[3] = 2;
         vals2[7] = 3;
         vals2[11] = 4;
         const a2 = tf.tensor(vals2, [batch, n, n]);
         const b2 = tf.tensor(vals2, [batch, n, n]);
         const result2 = tf.matMul(a2, b2);
         expect(result2.shape).toEqual([batch, n, n]);
         expectArraysClose(
             await result2.data(), [0, 0, 0, 4, 0, 0, 0, 9, 0, 0, 0, 16]);
       });

    it('batched matmul with the matrices being vectors transposedA',
       async () => {
         const batch = 3;
         const sharedDim = MATMUL_SHARED_DIM_THRESHOLD + 1;
         const values = new Float32Array(batch * sharedDim);
         values[10] = 2;

         const a = tf.tensor(values, [batch, sharedDim, 1]);
         const b = tf.tensor(values, [batch, sharedDim, 1]);
         const transposeA = true;
         const transposeB = false;
         const result = tf.matMul(a, b, transposeA, transposeB);
         expect(result.shape).toEqual([batch, 1, 1]);
         expectArraysClose(await result.data(), [4, 0, 0]);
       });

    it('batched matmul with the matrices being vectors transposedB',
       async () => {
         const batch = 3;
         const sharedDim = MATMUL_SHARED_DIM_THRESHOLD + 1;
         const values = new Float32Array(batch * sharedDim);
         values[10] = 2;

         const a = tf.tensor(values, [batch, 1, sharedDim]);
         const b = tf.tensor(values, [batch, 1, sharedDim]);
         const transposeA = false;
         const transposeB = true;
         const result = tf.matMul(a, b, transposeA, transposeB);
         expect(result.shape).toEqual([batch, 1, 1]);
         expectArraysClose(await result.data(), [4, 0, 0]);
       });

    it('batched matmul with matrix x vector', async () => {
      const batch = 3;
      const sharedDim = MATMUL_SHARED_DIM_THRESHOLD + 1;
      const values = new Float32Array(batch * sharedDim);
      values[10] = 2;

      const a = tf.ones([batch, 2, sharedDim]);
      const b = tf.tensor(values, [batch, sharedDim, 1]);
      const result = tf.matMul(a, b);
      expect(result.shape).toEqual([batch, 2, 1]);
      expectArraysClose(await result.data(), [2, 2, 0, 0, 0, 0]);
    });

    it('batched matmul with matrix x vector transposedA', async () => {
      const batch = 3;
      const sharedDim = MATMUL_SHARED_DIM_THRESHOLD + 1;
      const values = new Float32Array(batch * sharedDim);
      values[10] = 2;

      const a = tf.ones([batch, sharedDim, 2]);
      const b = tf.tensor(values, [batch, sharedDim, 1]);
      const transposeA = true;
      const transposeB = false;
      const result = tf.matMul(a, b, transposeA, transposeB);
      expect(result.shape).toEqual([batch, 2, 1]);
      expectArraysClose(await result.data(), [2, 2, 0, 0, 0, 0]);
    });

    it('batched matmul with matrix x vector transposedB', async () => {
      const batch = 3;
      const sharedDim = MATMUL_SHARED_DIM_THRESHOLD + 1;
      const values = new Float32Array(batch * sharedDim);
      values[10] = 2;

      const a = tf.ones([batch, 2, sharedDim]);
      const b = tf.tensor(values, [batch, 1, sharedDim]);
      const transposeA = false;
      const transposeB = true;
      const result = tf.matMul(a, b, transposeA, transposeB);
      expect(result.shape).toEqual([batch, 2, 1]);
      expectArraysClose(await result.data(), [2, 2, 0, 0, 0, 0]);
    });

    it('batched matmul with vector x matrix', async () => {
      const batch = 3;
      const sharedDim = MATMUL_SHARED_DIM_THRESHOLD + 1;
      const values = new Float32Array(batch * sharedDim);
      values[10] = 2;

      const a = tf.tensor(values, [batch, 1, sharedDim]);
      const b = tf.ones([batch, sharedDim, 2]);
      const result = tf.matMul(a, b);
      expect(result.shape).toEqual([batch, 1, 2]);
      expectArraysClose(await result.data(), [2, 2, 0, 0, 0, 0]);
    });

    it('batched matmul with vector x matrix transposedA', async () => {
      const batch = 3;
      const sharedDim = MATMUL_SHARED_DIM_THRESHOLD + 1;
      const values = new Float32Array(batch * sharedDim);
      values[10] = 2;

      const a = tf.tensor(values, [batch, sharedDim, 1]);
      const b = tf.ones([batch, sharedDim, 2]);
      const transposeA = true;
      const transposeB = false;
      const result = tf.matMul(a, b, transposeA, transposeB);
      expect(result.shape).toEqual([batch, 1, 2]);
      expectArraysClose(await result.data(), [2, 2, 0, 0, 0, 0]);
    });

    it('batched matmul with vector x matrix transposedB', async () => {
      const batch = 3;
      const sharedDim = MATMUL_SHARED_DIM_THRESHOLD + 1;
      const values = new Float32Array(batch * sharedDim);
      values[10] = 2;

      const a = tf.tensor(values, [batch, 1, sharedDim]);
      const b = tf.ones([batch, 2, sharedDim]);
      const transposeA = false;
      const transposeB = true;
      const result = tf.matMul(a, b, transposeA, transposeB);
      expect(result.shape).toEqual([batch, 1, 2]);
      expectArraysClose(await result.data(), [2, 2, 0, 0, 0, 0]);
    });

    it('A x B', async () => {
      const a = tf.tensor3d(
          [
            -5, -5, -6, 8, -2, -8, 4, -7, -6, -9, -1, 3,  7,  -2, 5,
            -6, 3,  8,  7, -8, 1,  4, -4, 6,  4,  -4, -9, -5, 2,  -2
          ],
          [5, 2, 3]);
      const b = tf.tensor3d(
          [
            -8, -4, -1, 0,  -7, 0, 3,  3,  6,   2,  -1, 8, -4, 9, -6,
            5,  8,  9,  -9, 7,  0, -1, -1, -10, -7, 3,  4, 6,  3, -4
          ],
          [5, 3, 2]);

      const c = tf.matMul(a, b);
      expect(c.shape).toEqual([5, 2, 2]);
      expectArraysClose(await c.data(), [
        87, 20, -6,  -32, -24, -50, -36, -5, 24, 98,
        70, 33, -64, 47,  -42, -28, -71, 24, 37, 5
      ]);
    });

    it('A x B in 4D', async () => {
      const a = tf.tensor4d(
          [
            -2, 3,  5,  -5, 3,  9,  -3, -5, 1,   1,  -9, 9,   -6, 6,  -8,
            -7, -1, 3,  9,  -7, -7, 2,  10, -6,  -8, -6, 9,   -6, 4,  -1,
            9,  -6, 10, 8,  -9, 5,  -8, -7, 0,   2,  -5, -1,  -9, -4, 3,
            -2, 6,  -4, 7,  1,  -5, -4, 9,  -8,  -6, -8, 4,   -1, 4,  3,
            -7, 8,  -7, 5,  -3, -2, -4, 9,  2,   -1, 1,  -10, -3, 5,  -4,
            6,  -8, -8, 9,  -3, -5, 10, 3,  -3,  -3, 9,  3,   -3, 2,  -8,
            10, 1,  9,  -2, -2, -3, -4, 6,  -10, -1, 8,  -8,  7,  3,  -2,
            3,  6,  -2, -2, -4, 1,  -5, -4, 0,   5,  1,  9,   -8, -2, -1
          ],
          [4, 5, 2, 3]);
      const b = tf.tensor4d(
          [
            -4, -3, -2, -6, 6,  -1, -4, -1, 7,  -4, 8,  -9,  -9, 0,   -1,
            -4, -6, -7, -3, -4, -7, 6,  -8, 1,  -2, 1,  -1,  -3, 8,   -5,
            9,  -2, 5,  9,  -2, 2,  -5, -5, -8, -1, -2, -3,  -2, -10, 6,
            -3, 0,  1,  6,  7,  1,  2,  -4, -5, 2,  -5, -7,  9,  3,   -6,
            6,  4,  -4, 6,  10, -3, -2, 8,  10, -8, 10, -1,  -9, -7,  -8,
            -3, 1,  1,  -2, -9, -7, -6, -1, 0,  7,  -9, -7,  -5, 0,   -4,
            -4, -7, 2,  4,  6,  6,  -4, -6, -8, 3,  -8, -9,  6,  9,   -4,
            1,  -1, 0,  8,  9,  0,  -5, 3,  -1, 5,  0,  -10, 7,  -2,  6
          ],
          [4, 5, 3, 2]);

      const transposeA = false;
      const transposeB = false;
      const c = tf.matMul(a, b, transposeA, transposeB);

      expectArraysClose(await c.data(), [
        32,  -17, 68,  -12,  -15, 14,  5,   -46, 96,  32,  46,  -17, 78,   -85,
        -28, 46,  94,  -35,  0,   -13, 31,  -52, 17,  -87, 96,  47,  32,   -2,
        -6,  105, 40,  -2,   63,  76,  17,  30,  56,  -66, -21, 23,  -144, 41,
        22,  8,   118, -106, -88, -6,  -17, 2,   2,   -26, 8,   -63, -38,  -108,
        -84, -30, -35, 49,   16,  -12, -14, -12, 48,  132, 4,   102, 32,   66,
        -4,  33,  -13, 1,    -40, -25, -3,  61,  -18, -20
      ]);
    });

    it('A x B^t', async () => {
      const a = tf.tensor3d(
          [
            -5, -5, -6, 8, -2, -8, 4, -7, -6, -9, -1, 3,  7,  -2, 5,
            -6, 3,  8,  7, -8, 1,  4, -4, 6,  4,  -4, -9, -5, 2,  -2
          ],
          [5, 2, 3]);
      const b = tf.tensor3d(
          [
            -8, -4, -1, 0,  -7, 0, 3,  3,  6,   2,  -1, 8, -4, 9, -6,
            5,  8,  9,  -9, 7,  0, -1, -1, -10, -7, 3,  4, 6,  3, -4
          ],
          [5, 2, 3]);

      const transposeA = false;
      const transposeB = true;
      const c = tf.matMul(a, b, transposeA, transposeB);
      expect(c.shape).toEqual([5, 2, 2]);
      expectArraysClose(await c.data(), [
        66, 35, -48,  14, -45, -33, -12, 7,  -76, 64,
        3,  66, -119, -9, -64, -60, -76, 48, 33,  -16
      ]);
    });

    it('A^t x B', async () => {
      const a = tf.tensor3d(
          [
            -5, -5, -6, 8, -2, -8, 4, -7, -6, -9, -1, 3,  7,  -2, 5,
            -6, 3,  8,  7, -8, 1,  4, -4, 6,  4,  -4, -9, -5, 2,  -2
          ],
          [5, 2, 3]);
      const b = tf.tensor3d(
          [
            -8, -4, -1, 0,  -7, 0, 3,  3,  6,   2,  -1, 8, -4, 9, -6,
            5,  8,  9,  -9, 7,  0, -1, -1, -10, -7, 3,  4, 6,  3, -4
          ],
          [5, 2, 3]);

      const transposeA = true;
      const transposeB = false;
      const c = tf.matMul(a, b, transposeA, transposeB);

      expectArraysClose(await c.data(), [
        40,  -36, 5,   40,  34, 5,   48,  80, 6,  -6, 21,  -48, -23, -20, -50,
        -12, -21, -12, -58, 15, -96, 23,  6,  39, 20, 109, 42,  -67, 45,  -40,
        76,  -52, 40,  -15, 1,  -60, -58, -3, 36, 40, -6,  -24, 51,  -33, -28
      ]);
    });

    it('A^t x B in 4D', async () => {
      const a = tf.tensor4d(
          [
            -2, 3,  5,  -5, 3,  9,  -3, -5, 1,   1,  -9, 9,   -6, 6,  -8,
            -7, -1, 3,  9,  -7, -7, 2,  10, -6,  -8, -6, 9,   -6, 4,  -1,
            9,  -6, 10, 8,  -9, 5,  -8, -7, 0,   2,  -5, -1,  -9, -4, 3,
            -2, 6,  -4, 7,  1,  -5, -4, 9,  -8,  -6, -8, 4,   -1, 4,  3,
            -7, 8,  -7, 5,  -3, -2, -4, 9,  2,   -1, 1,  -10, -3, 5,  -4,
            6,  -8, -8, 9,  -3, -5, 10, 3,  -3,  -3, 9,  3,   -3, 2,  -8,
            10, 1,  9,  -2, -2, -3, -4, 6,  -10, -1, 8,  -8,  7,  3,  -2,
            3,  6,  -2, -2, -4, 1,  -5, -4, 0,   5,  1,  9,   -8, -2, -1
          ],
          [4, 5, 2, 3]);
      const b = tf.tensor4d(
          [
            -4, -3, -2, -6, 6,  -1, -4, -1, 7,  -4, 8,  -9,  -9, 0,   -1,
            -4, -6, -7, -3, -4, -7, 6,  -8, 1,  -2, 1,  -1,  -3, 8,   -5,
            9,  -2, 5,  9,  -2, 2,  -5, -5, -8, -1, -2, -3,  -2, -10, 6,
            -3, 0,  1,  6,  7,  1,  2,  -4, -5, 2,  -5, -7,  9,  3,   -6,
            6,  4,  -4, 6,  10, -3, -2, 8,  10, -8, 10, -1,  -9, -7,  -8,
            -3, 1,  1,  -2, -9, -7, -6, -1, 0,  7,  -9, -7,  -5, 0,   -4,
            -4, -7, 2,  4,  6,  6,  -4, -6, -8, 3,  -8, -9,  6,  9,   -4,
            1,  -1, 0,  8,  9,  0,  -5, 3,  -1, 5,  0,  -10, 7,  -2,  6
          ],
          [4, 5, 2, 3]);

      const transposeA = true;
      const transposeB = false;
      const c = tf.matMul(a, b, transposeA, transposeB);

      expectArraysClose(await c.data(), [
        38,  -24, 9,   -30, 9,   -9,  -74,  39,  -19,  8,    11,  -30, 56,  -67,
        46,  -40, 71,  -74, 82,  42,  55,   -50, 6,    1,    60,  -18, -13, -15,
        -52, -61, 81,  -52, 59,  -15, 76,   43,  34,   -56,  38,  0,   26,  -14,
        -15, 1,   -4,  153, -34, 61,  -135, 30,  -48,  135,  -30, 60,  38,  36,
        58,  40,  45,  71,  1,   2,   3,    24,  90,   -56,  -10, 40,  -18, 6,
        -30, 14,  34,  65,  27,  24,  -29,  -44, -46,  -3,   35,  -21, 27,  48,
        20,  52,  32,  35,  -11, -46, -12,  22,  13,   30,   2,   -23, -54, -48,
        34,  16,  -42, -39, -26, 82,  89,   76,  -84,  30,   9,   27,  30,  -21,
        -43, -48, 60,  20,  24,  -78, -91,  -63, -12,  24,   21,  28,  48,  35,
        -6,  27,  33,  53,  -81, -71, 61,   -27, 11,   -48,  -82, 8,   -12, -19,
        -10, -48, -81, 0,   13,  32,  41,   0,   -100, -120, 16,  124, 152, 45,
        60,  -28, 24,  21,  -12, -14, -16,  8,   9,    -33,  5,   -12, -48, 4,
        8,   9,   0,   -31, 16,  -98, -9,   4,   -22,  38,   2,   -96
      ]);
    });

    it('A^t x B^t', async () => {
      const a = tf.tensor3d(
          [
            -5, -5, -6, 8, -2, -8, 4, -7, -6, -9, -1, 3,  7,  -2, 5,
            -6, 3,  8,  7, -8, 1,  4, -4, 6,  4,  -4, -9, -5, 2,  -2
          ],
          [5, 3, 2]);
      const b = tf.tensor3d(
          [
            -8, -4, -1, 0,  -7, 0, 3,  3,  6,   2,  -1, 8, -4, 9, -6,
            5,  8,  9,  -9, 7,  0, -1, -1, -10, -7, 3,  4, 6,  3, -4
          ],
          [5, 2, 3]);

      const transposeA = true;
      const transposeB = true;
      const c = tf.matMul(a, b, transposeA, transposeB);
      expectArraysClose(await c.data(), [
        66,  42, 16,  -56, -12, 6,   -30, 19,  -1, 102,
        -94, 14, -56, 32,  100, -56, -47, -11, 5,  -31
      ]);
    });
  };
}

for (let i = 0; i < MatMulProgramType.MatMulMax; i++) {
  describeWithFlags(`matmul ${MatMulProgramType[i]}`, ALL_ENVS, matmulTest(i));
  // Skip MatMulSplitKProgram since it doesn't support batch > 1;
  if (i !== MatMulProgramType.MatMulSplitKProgram) {
    describeWithFlags(
        `matmulBatch ${MatMulProgramType[i]}`, ALL_ENVS, matmulBatchTest(i));
  }
}
