diff --git a/src/resources/cache/hashes.json b/src/resources/cache/hashes.json index 9476d8431f41..48c819594290 100644 --- a/src/resources/cache/hashes.json +++ b/src/resources/cache/hashes.json @@ -1,107 +1,110 @@ { - "webgpu/shader/execution/binary/af_addition.bin": "38b261fa", - "webgpu/shader/execution/binary/af_logical.bin": "a483b968", - "webgpu/shader/execution/binary/af_division.bin": "ec39b0da", - "webgpu/shader/execution/binary/af_matrix_addition.bin": "ca1373a8", - "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "406d99af", - "webgpu/shader/execution/binary/af_multiplication.bin": "2eb6d50d", - "webgpu/shader/execution/binary/af_remainder.bin": "e2b6b21", - "webgpu/shader/execution/binary/af_subtraction.bin": "84794350", - "webgpu/shader/execution/binary/f16_addition.bin": "19e8823d", - "webgpu/shader/execution/binary/f16_logical.bin": "b89ca9b9", - "webgpu/shader/execution/binary/f16_division.bin": "6dc4b748", - "webgpu/shader/execution/binary/f16_matrix_addition.bin": "7533842", - "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "2d799920", - "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "44e3b295", - "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "412f0911", - "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "a231201b", - "webgpu/shader/execution/binary/f16_multiplication.bin": "94b11030", - "webgpu/shader/execution/binary/f16_remainder.bin": "de68a200", - "webgpu/shader/execution/binary/f16_subtraction.bin": "f308327a", - "webgpu/shader/execution/binary/f32_addition.bin": "c87c8c08", - "webgpu/shader/execution/binary/f32_logical.bin": "c7370c09", - "webgpu/shader/execution/binary/f32_division.bin": "34ce65ae", - "webgpu/shader/execution/binary/f32_matrix_addition.bin": "f3808d0c", - "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "e33e7fe5", - "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "41091ebf", - "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "37ccb101", - "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "4d67866", - "webgpu/shader/execution/binary/f32_multiplication.bin": "5d85a36c", - "webgpu/shader/execution/binary/f32_remainder.bin": "62f591b2", - "webgpu/shader/execution/binary/f32_subtraction.bin": "60fc275a", - "webgpu/shader/execution/binary/i32_arithmetic.bin": "a0b0a016", - "webgpu/shader/execution/binary/i32_comparison.bin": "f3d9b3f9", - "webgpu/shader/execution/binary/u32_arithmetic.bin": "16e32fd", - "webgpu/shader/execution/binary/u32_comparison.bin": "da33cc5d", - "webgpu/shader/execution/abs.bin": "1ead834c", - "webgpu/shader/execution/acos.bin": "e25802ba", - "webgpu/shader/execution/acosh.bin": "2321726f", - "webgpu/shader/execution/asin.bin": "d554a73b", - "webgpu/shader/execution/asinh.bin": "d2bdb21b", - "webgpu/shader/execution/atan.bin": "eb6476f3", - "webgpu/shader/execution/atan2.bin": "cf15e7fa", - "webgpu/shader/execution/atanh.bin": "6c57cc3", - "webgpu/shader/execution/bitcast.bin": "a25e9714", - "webgpu/shader/execution/ceil.bin": "8d120ea3", - "webgpu/shader/execution/clamp.bin": "a762ef58", - "webgpu/shader/execution/cos.bin": "a859da89", - "webgpu/shader/execution/cosh.bin": "86abdd85", - "webgpu/shader/execution/cross.bin": "e4556729", - "webgpu/shader/execution/degrees.bin": "1fa19a41", - "webgpu/shader/execution/determinant.bin": "108c3d65", - "webgpu/shader/execution/distance.bin": "77a1baa6", - "webgpu/shader/execution/dot.bin": "d4ac2e8a", - "webgpu/shader/execution/exp.bin": "15539afd", - "webgpu/shader/execution/exp2.bin": "7f6a8523", - "webgpu/shader/execution/faceForward.bin": "e7b35f43", - "webgpu/shader/execution/floor.bin": "b26656ca", - "webgpu/shader/execution/fma.bin": "5a70c683", - "webgpu/shader/execution/fract.bin": "23c0d5ec", - "webgpu/shader/execution/frexp.bin": "d28e66be", - "webgpu/shader/execution/inverseSqrt.bin": "9f297854", - "webgpu/shader/execution/ldexp.bin": "638db0c7", - "webgpu/shader/execution/length.bin": "7d237c62", - "webgpu/shader/execution/log.bin": "70720bf0", - "webgpu/shader/execution/log2.bin": "93a309be", - "webgpu/shader/execution/max.bin": "36eb4779", - "webgpu/shader/execution/min.bin": "ca772bf1", - "webgpu/shader/execution/mix.bin": "ecbf61ae", - "webgpu/shader/execution/modf.bin": "6ddea900", - "webgpu/shader/execution/normalize.bin": "d3e47c61", - "webgpu/shader/execution/pack2x16float.bin": "e6859c1a", - "webgpu/shader/execution/pow.bin": "a58be71c", - "webgpu/shader/execution/quantizeToF16.bin": "eca85bca", - "webgpu/shader/execution/radians.bin": "a216c9aa", - "webgpu/shader/execution/reflect.bin": "ebce9830", - "webgpu/shader/execution/refract.bin": "59d1e5d6", - "webgpu/shader/execution/round.bin": "9389a090", - "webgpu/shader/execution/saturate.bin": "7ca4b681", - "webgpu/shader/execution/sign.bin": "1f4eeb34", - "webgpu/shader/execution/sin.bin": "a1e234b4", - "webgpu/shader/execution/sinh.bin": "1a62054b", - "webgpu/shader/execution/smoothstep.bin": "d5824fd6", - "webgpu/shader/execution/sqrt.bin": "66f21d02", - "webgpu/shader/execution/step.bin": "310cb6c7", - "webgpu/shader/execution/tan.bin": "1e26f533", - "webgpu/shader/execution/tanh.bin": "4c546d1c", - "webgpu/shader/execution/transpose.bin": "7bef2494", - "webgpu/shader/execution/trunc.bin": "e72535eb", - "webgpu/shader/execution/unpack2x16float.bin": "593d88c6", - "webgpu/shader/execution/unpack2x16snorm.bin": "9ebd3e40", - "webgpu/shader/execution/unpack2x16unorm.bin": "83a36fa9", - "webgpu/shader/execution/unpack4x8snorm.bin": "41b12606", - "webgpu/shader/execution/unpack4x8unorm.bin": "96f1850b", - "webgpu/shader/execution/unary/af_arithmetic.bin": "6fa1d84a", - "webgpu/shader/execution/unary/af_assignment.bin": "98c8f82a", + "webgpu/shader/execution/binary/af_addition.bin": "de575056", + "webgpu/shader/execution/binary/af_logical.bin": "dc2105f8", + "webgpu/shader/execution/binary/af_division.bin": "d7e6d98f", + "webgpu/shader/execution/binary/af_matrix_addition.bin": "c215cf6d", + "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "57892276", + "webgpu/shader/execution/binary/af_multiplication.bin": "4c282ac2", + "webgpu/shader/execution/binary/af_remainder.bin": "9fdddf97", + "webgpu/shader/execution/binary/af_subtraction.bin": "a27de3c1", + "webgpu/shader/execution/binary/f16_addition.bin": "ecc2aa17", + "webgpu/shader/execution/binary/f16_logical.bin": "1851f647", + "webgpu/shader/execution/binary/f16_division.bin": "2cfec6de", + "webgpu/shader/execution/binary/f16_matrix_addition.bin": "f5b6ef4f", + "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "c47070a0", + "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "30b9d67c", + "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "46b631ba", + "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "19e6a937", + "webgpu/shader/execution/binary/f16_multiplication.bin": "8fbfc97c", + "webgpu/shader/execution/binary/f16_remainder.bin": "66cd384c", + "webgpu/shader/execution/binary/f16_subtraction.bin": "8b5fed3d", + "webgpu/shader/execution/binary/f32_addition.bin": "2ef1211a", + "webgpu/shader/execution/binary/f32_logical.bin": "3c97c69d", + "webgpu/shader/execution/binary/f32_division.bin": "2867ef0a", + "webgpu/shader/execution/binary/f32_matrix_addition.bin": "da9390d1", + "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "2d67296e", + "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "c79709f5", + "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "38b7c05f", + "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "f9b675d7", + "webgpu/shader/execution/binary/f32_multiplication.bin": "bb7ee512", + "webgpu/shader/execution/binary/f32_remainder.bin": "e0d16b8f", + "webgpu/shader/execution/binary/f32_subtraction.bin": "755fc63", + "webgpu/shader/execution/binary/i32_arithmetic.bin": "3c1d6f0f", + "webgpu/shader/execution/binary/i32_comparison.bin": "4759dfea", + "webgpu/shader/execution/binary/u32_arithmetic.bin": "6bf6989d", + "webgpu/shader/execution/binary/u32_comparison.bin": "ca8b140b", + "webgpu/shader/execution/abs.bin": "a79b85f3", + "webgpu/shader/execution/acos.bin": "eed1c72", + "webgpu/shader/execution/acosh.bin": "a1b7dc12", + "webgpu/shader/execution/asin.bin": "fbf69cb0", + "webgpu/shader/execution/asinh.bin": "7b8f7a8", + "webgpu/shader/execution/atan.bin": "250334d8", + "webgpu/shader/execution/atan2.bin": "9df3f787", + "webgpu/shader/execution/atanh.bin": "5c79c30d", + "webgpu/shader/execution/bitcast.bin": "964fdecd", + "webgpu/shader/execution/ceil.bin": "246bf087", + "webgpu/shader/execution/clamp.bin": "3a299eaf", + "webgpu/shader/execution/cos.bin": "d3efc52b", + "webgpu/shader/execution/cosh.bin": "867cbf85", + "webgpu/shader/execution/cross.bin": "a1089567", + "webgpu/shader/execution/degrees.bin": "d1cfaeac", + "webgpu/shader/execution/determinant.bin": "44faf0f8", + "webgpu/shader/execution/distance.bin": "e1191c92", + "webgpu/shader/execution/dot.bin": "242201b", + "webgpu/shader/execution/exp.bin": "e5f97f39", + "webgpu/shader/execution/exp2.bin": "65bd37ec", + "webgpu/shader/execution/faceForward.bin": "ebb6017a", + "webgpu/shader/execution/floor.bin": "a24e0ff8", + "webgpu/shader/execution/fma.bin": "87615a5f", + "webgpu/shader/execution/fract.bin": "eab1b9fa", + "webgpu/shader/execution/frexp.bin": "7dd8033", + "webgpu/shader/execution/inverseSqrt.bin": "356b47c5", + "webgpu/shader/execution/ldexp.bin": "788fdf3e", + "webgpu/shader/execution/length.bin": "69f13c20", + "webgpu/shader/execution/log.bin": "dc9c311c", + "webgpu/shader/execution/log2.bin": "d1a49443", + "webgpu/shader/execution/max.bin": "6750f2eb", + "webgpu/shader/execution/min.bin": "c8200395", + "webgpu/shader/execution/mix.bin": "86c40712", + "webgpu/shader/execution/modf.bin": "50483a83", + "webgpu/shader/execution/normalize.bin": "244a8e05", + "webgpu/shader/execution/pack2x16float.bin": "dcd8656d", + "webgpu/shader/execution/pow.bin": "633c917a", + "webgpu/shader/execution/quantizeToF16.bin": "f6044bd2", + "webgpu/shader/execution/radians.bin": "a90b21ea", + "webgpu/shader/execution/reflect.bin": "670fbba2", + "webgpu/shader/execution/refract.bin": "63b06feb", + "webgpu/shader/execution/round.bin": "d4c09bde", + "webgpu/shader/execution/saturate.bin": "d4f8a4d0", + "webgpu/shader/execution/sign.bin": "57c988b9", + "webgpu/shader/execution/sin.bin": "59aab9f5", + "webgpu/shader/execution/sinh.bin": "3890a90c", + "webgpu/shader/execution/smoothstep.bin": "b695fd45", + "webgpu/shader/execution/sqrt.bin": "9524c93", + "webgpu/shader/execution/step.bin": "b9cc90a4", + "webgpu/shader/execution/tan.bin": "e5792957", + "webgpu/shader/execution/tanh.bin": "ba99c688", + "webgpu/shader/execution/transpose.bin": "83588805", + "webgpu/shader/execution/trunc.bin": "aad5d037", + "webgpu/shader/execution/unpack2x16float.bin": "493cbe7b", + "webgpu/shader/execution/unpack2x16snorm.bin": "fd0b5eb9", + "webgpu/shader/execution/unpack2x16unorm.bin": "f7436a6c", + "webgpu/shader/execution/unpack4x8snorm.bin": "eca842d9", + "webgpu/shader/execution/unpack4x8unorm.bin": "8654f67e", + "webgpu/shader/execution/unary/af_arithmetic.bin": "e05d3c45", + "webgpu/shader/execution/unary/af_assignment.bin": "45da8cfe", "webgpu/shader/execution/unary/bool_conversion.bin": "dd71f171", - "webgpu/shader/execution/unary/f16_arithmetic.bin": "2f2d38fc", - "webgpu/shader/execution/unary/f16_conversion.bin": "70c94538", - "webgpu/shader/execution/unary/f32_arithmetic.bin": "db90c01c", - "webgpu/shader/execution/unary/f32_conversion.bin": "81912140", + "webgpu/shader/execution/unary/f16_arithmetic.bin": "9c17fdca", + "webgpu/shader/execution/unary/f16_conversion.bin": "c02b6c8", + "webgpu/shader/execution/unary/f32_arithmetic.bin": "feff26f7", + "webgpu/shader/execution/unary/f32_conversion.bin": "f2639f4c", "webgpu/shader/execution/unary/i32_arithmetic.bin": "c69716e2", "webgpu/shader/execution/unary/i32_conversion.bin": "83218e69", "webgpu/shader/execution/unary/u32_conversion.bin": "8f5bad00", "webgpu/shader/execution/unary/ai_assignment.bin": "c7e6ac33", - "webgpu/shader/execution/binary/ai_arithmetic.bin": "81c11ec2", - "webgpu/shader/execution/unary/ai_arithmetic.bin": "3d27dc97" + "webgpu/shader/execution/binary/ai_arithmetic.bin": "dfcd593a", + "webgpu/shader/execution/unary/ai_arithmetic.bin": "3d27dc97", + "webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin": "7e551ea1", + "webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin": "fe7ea65b", + "webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin": "2a98deaa" } \ No newline at end of file diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin new file mode 100644 index 000000000000..5f8636b77c7d Binary files /dev/null and b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin differ diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin new file mode 100644 index 000000000000..a8d35f964d4e Binary files /dev/null and b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin differ diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin new file mode 100644 index 000000000000..0a61c01c1a46 Binary files /dev/null and b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin differ diff --git a/src/unittests/floating_point.spec.ts b/src/unittests/floating_point.spec.ts index 23bfaafc2268..ad27c1d711d8 100644 --- a/src/unittests/floating_point.spec.ts +++ b/src/unittests/floating_point.spec.ts @@ -7193,7 +7193,7 @@ g.test('subtractionMatrixMatrixInterval') g.test('multiplicationMatrixMatrixInterval') .params(u => u - .combine('trait', ['f32', 'f16'] as const) + .combine('trait', ['f32', 'f16', 'abstract'] as const) .beginSubcases() .combineWithParams([ // Only testing that different shapes of matrices are handled correctly @@ -7768,12 +7768,26 @@ const kMultiplicationMatrixScalarIntervalCases = { ], }, ] as MatrixScalarToMatrixCase[], + abstract: [ + // From https://github.com/gpuweb/cts/issues/3044 + { + matrix: [ + [kValue.f64.negative.min, 0], + [0, 0], + ], + scalar: kValue.f64.negative.subnormal.min, + expected: [ + [[0, reinterpretU64AsF64(0x400ffffffffffffdn)], 0], // [[0, 3.9999995...], 0], + [0, 0], + ], + }, + ] as MatrixScalarToMatrixCase[], } as const; g.test('multiplicationMatrixScalarInterval') .params(u => u - .combine('trait', ['f32', 'f16'] as const) + .combine('trait', ['f32', 'f16', 'abstract'] as const) .beginSubcases() .expandWithParams(p => { const trait = FP[p.trait]; @@ -7945,7 +7959,7 @@ interface MatrixVectorToVectorCase { g.test('multiplicationMatrixVectorInterval') .params(u => u - .combine('trait', ['f32', 'f16'] as const) + .combine('trait', ['f32', 'f16', 'abstract'] as const) .beginSubcases() .combineWithParams([ // Only testing that different shapes of matrices are handled correctly @@ -8062,7 +8076,7 @@ interface VectorMatrixToVectorCase { g.test('multiplicationVectorMatrixInterval') .params(u => u - .combine('trait', ['f32', 'f16'] as const) + .combine('trait', ['f32', 'f16', 'abstract'] as const) .beginSubcases() .combineWithParams([ // Only testing that different shapes of matrices are handled correctly @@ -8070,8 +8084,8 @@ g.test('multiplicationVectorMatrixInterval') // multiplicationVectorMatrixInterval uses DotIntervalOp for calculating // intervals, so the testing for dotInterval covers the actual interval // calculations. - // Keep all expected result integer no larger than 2047 to ensure that all result is exactly - // represeantable in both f32 and f16. + // Keep all expected result integer no larger than 2047 to ensure that + // all result is exactly representable in both f32 and f16. { vector: [1, 2], matrix: [ diff --git a/src/webgpu/listing_meta.json b/src/webgpu/listing_meta.json index 95851c200be1..a046cec8e64f 100644 --- a/src/webgpu/listing_meta.json +++ b/src/webgpu/listing_meta.json @@ -914,7 +914,12 @@ "webgpu:shader,execution,expression,binary,af_division:vector:*": { "subcaseMS": 237.134 }, "webgpu:shader,execution,expression,binary,af_division:vector_scalar:*": { "subcaseMS": 580.000 }, "webgpu:shader,execution,expression,binary,af_matrix_addition:matrix:*": { "subcaseMS": 11169.534 }, + "webgpu:shader,execution,expression,binary,af_matrix_matrix_multiplication:matrix_matrix:*": { "subcaseMS": 0.000 }, + "webgpu:shader,execution,expression,binary,af_matrix_scalar_multiplication:matrix_scalar:*": { "subcaseMS": 0.000 }, + "webgpu:shader,execution,expression,binary,af_matrix_scalar_multiplication:scalar_matrix:*": { "subcaseMS": 0.000 }, "webgpu:shader,execution,expression,binary,af_matrix_subtraction:matrix:*": { "subcaseMS": 14060.956 }, + "webgpu:shader,execution,expression,binary,af_matrix_vector_multiplication:matrix_vector:*": { "subcaseMS": 0.000 }, + "webgpu:shader,execution,expression,binary,af_matrix_vector_multiplication:vector_matrix:*": { "subcaseMS": 0.000 }, "webgpu:shader,execution,expression,binary,af_multiplication:scalar:*": { "subcaseMS": 777.901 }, "webgpu:shader,execution,expression,binary,af_multiplication:scalar_vector:*": { "subcaseMS": 2025.534 }, "webgpu:shader,execution,expression,binary,af_multiplication:vector:*": { "subcaseMS": 710.667 }, diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.cache.ts new file mode 100644 index 000000000000..c7540083d6ff --- /dev/null +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.cache.ts @@ -0,0 +1,28 @@ +import { FP } from '../../../../util/floating_point.js'; +import { sparseMatrixF64Range } from '../../../../util/math.js'; +import { selectNCases } from '../case.js'; +import { makeCaseCache } from '../case_cache.js'; + +// Cases: matKxR_matCxK +const mat_mat_cases = ([2, 3, 4] as const) + .flatMap(k => + ([2, 3, 4] as const).flatMap(cols => + ([2, 3, 4] as const).map(rows => ({ + [`mat${k}x${rows}_mat${cols}x${k}`]: () => { + return selectNCases( + 'binary/af_matrix_matrix_multiplication', + 50, + FP.abstract.generateMatrixPairToMatrixCases( + sparseMatrixF64Range(k, rows), + sparseMatrixF64Range(cols, k), + 'finite', + FP.abstract.multiplicationMatrixMatrixInterval + ) + ); + }, + })) + ) + ) + .reduce((a, b) => ({ ...a, ...b }), {}); + +export const d = makeCaseCache('binary/af_matrix_matrix_multiplication', mat_mat_cases); diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.spec.ts new file mode 100644 index 000000000000..bb7fd668c296 --- /dev/null +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.spec.ts @@ -0,0 +1,48 @@ +export const description = ` +Execution Tests for matrix-matrix AbstractFloat multiplication expression +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../gpu_test.js'; +import { TypeAbstractFloat, TypeMat } from '../../../../util/conversion.js'; +import { onlyConstInputSource, run } from '../expression.js'; + +import { d } from './af_matrix_matrix_multiplication.cache.js'; +import { abstractFloatBinary } from './binary.js'; + +export const g = makeTestGroup(GPUTest); + +g.test('matrix_matrix') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x * y, where x is a matrix and y is a matrix +Accuracy: Correctly rounded +` + ) + .params(u => + u + .combine('inputSource', onlyConstInputSource) + .combine('common_dim', [2, 3, 4] as const) + .combine('x_rows', [2, 3, 4] as const) + .combine('y_cols', [2, 3, 4] as const) + ) + .beforeAllSubcases(t => { + t.selectDeviceOrSkipTestCase({ requiredFeatures: ['shader-f16'] }); + }) + .fn(async t => { + const x_cols = t.params.common_dim; + const x_rows = t.params.x_rows; + const y_cols = t.params.y_cols; + const y_rows = t.params.common_dim; + + const cases = await d.get(`mat${x_cols}x${x_rows}_mat${y_cols}x${y_rows}`); + await run( + t, + abstractFloatBinary('*'), + [TypeMat(x_cols, x_rows, TypeAbstractFloat), TypeMat(y_cols, y_rows, TypeAbstractFloat)], + TypeMat(y_cols, x_rows, TypeAbstractFloat), + t.params, + cases + ); + }); diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_scalar_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_scalar_multiplication.cache.ts new file mode 100644 index 000000000000..910636297022 --- /dev/null +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_scalar_multiplication.cache.ts @@ -0,0 +1,49 @@ +import { FP } from '../../../../util/floating_point.js'; +import { sparseMatrixF64Range, sparseScalarF64Range } from '../../../../util/math.js'; +import { selectNCases } from '../case.js'; +import { makeCaseCache } from '../case_cache.js'; + +// Cases: matCxR_scalar +const mat_scalar_cases = ([2, 3, 4] as const) + .flatMap(cols => + ([2, 3, 4] as const).map(rows => ({ + [`mat${cols}x${rows}_scalar`]: () => { + return selectNCases( + 'binary/af_matrix_scalar_multiplication_mat_scalar', + 50, + FP.abstract.generateMatrixScalarToMatrixCases( + sparseMatrixF64Range(cols, rows), + sparseScalarF64Range(), + 'finite', + FP.abstract.multiplicationMatrixScalarInterval + ) + ); + }, + })) + ) + .reduce((a, b) => ({ ...a, ...b }), {}); + +// Cases: scalar_matCxR +const scalar_mat_cases = ([2, 3, 4] as const) + .flatMap(cols => + ([2, 3, 4] as const).map(rows => ({ + [`scalar_mat${cols}x${rows}`]: () => { + return selectNCases( + 'binary/af_matrix_scalar_multiplication_scalar_mat', + 50, + FP.abstract.generateScalarMatrixToMatrixCases( + sparseScalarF64Range(), + sparseMatrixF64Range(cols, rows), + 'finite', + FP.abstract.multiplicationScalarMatrixInterval + ) + ); + }, + })) + ) + .reduce((a, b) => ({ ...a, ...b }), {}); + +export const d = makeCaseCache('binary/af_matrix_scalar_multiplication', { + ...mat_scalar_cases, + ...scalar_mat_cases, +}); diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_scalar_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_scalar_multiplication.spec.ts new file mode 100644 index 000000000000..05afa31275d6 --- /dev/null +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_scalar_multiplication.spec.ts @@ -0,0 +1,69 @@ +export const description = ` +Execution Tests for matrix-scalar and scalar-matrix AbstractFloat multiplication expression +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../gpu_test.js'; +import { TypeAbstractFloat, TypeMat } from '../../../../util/conversion.js'; +import { onlyConstInputSource, run } from '../expression.js'; + +import { d } from './af_matrix_scalar_multiplication.cache.js'; +import { abstractFloatBinary } from './binary.js'; + +export const g = makeTestGroup(GPUTest); + +g.test('matrix_scalar') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x * y, where x is a matrix and y is a scalar +Accuracy: Correctly rounded +` + ) + .params(u => + u + .combine('inputSource', onlyConstInputSource) + .combine('cols', [2, 3, 4] as const) + .combine('rows', [2, 3, 4] as const) + ) + .fn(async t => { + const cols = t.params.cols; + const rows = t.params.rows; + const cases = await d.get(`mat${cols}x${rows}_scalar`); + await run( + t, + abstractFloatBinary('*'), + [TypeMat(cols, rows, TypeAbstractFloat), TypeAbstractFloat], + TypeMat(cols, rows, TypeAbstractFloat), + t.params, + cases + ); + }); + +g.test('scalar_matrix') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x * y, where x is a scalar and y is a matrix +Accuracy: Correctly rounded +` + ) + .params(u => + u + .combine('inputSource', onlyConstInputSource) + .combine('cols', [2, 3, 4] as const) + .combine('rows', [2, 3, 4] as const) + ) + .fn(async t => { + const cols = t.params.cols; + const rows = t.params.rows; + const cases = await d.get(`scalar_mat${cols}x${rows}`); + await run( + t, + abstractFloatBinary('*'), + [TypeAbstractFloat, TypeMat(cols, rows, TypeAbstractFloat)], + TypeMat(cols, rows, TypeAbstractFloat), + t.params, + cases + ); + }); diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_vector_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_vector_multiplication.cache.ts new file mode 100644 index 000000000000..1401428d3da0 --- /dev/null +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_vector_multiplication.cache.ts @@ -0,0 +1,49 @@ +import { FP } from '../../../../util/floating_point.js'; +import { sparseMatrixF64Range, sparseVectorF64Range } from '../../../../util/math.js'; +import { selectNCases } from '../case.js'; +import { makeCaseCache } from '../case_cache.js'; + +// Cases: matCxR_vecC +const mat_vec_cases = ([2, 3, 4] as const) + .flatMap(cols => + ([2, 3, 4] as const).map(rows => ({ + [`mat${cols}x${rows}_vec${cols}`]: () => { + return selectNCases( + 'binary/af_matrix_vector_multiplication_mat_vec', + 50, + FP.abstract.generateMatrixVectorToVectorCases( + sparseMatrixF64Range(cols, rows), + sparseVectorF64Range(cols), + 'finite', + FP.abstract.multiplicationMatrixVectorInterval + ) + ); + }, + })) + ) + .reduce((a, b) => ({ ...a, ...b }), {}); + +// Cases: vecR_matCxR +const vec_mat_cases = ([2, 3, 4] as const) + .flatMap(rows => + ([2, 3, 4] as const).map(cols => ({ + [`vec${rows}_mat${cols}x${rows}`]: () => { + return selectNCases( + 'binary/af_matrix_vector_multiplication_vec_mat', + 50, + FP.abstract.generateVectorMatrixToVectorCases( + sparseVectorF64Range(rows), + sparseMatrixF64Range(cols, rows), + 'finite', + FP.abstract.multiplicationVectorMatrixInterval + ) + ); + }, + })) + ) + .reduce((a, b) => ({ ...a, ...b }), {}); + +export const d = makeCaseCache('binary/af_matrix_vector_multiplication', { + ...mat_vec_cases, + ...vec_mat_cases, +}); diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_vector_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_vector_multiplication.spec.ts new file mode 100644 index 000000000000..c464c442aa85 --- /dev/null +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_vector_multiplication.spec.ts @@ -0,0 +1,69 @@ +export const description = ` +Execution Tests for matrix-vector and vector-matrix AbstractFloat multiplication expression +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../gpu_test.js'; +import { TypeAbstractFloat, TypeMat, TypeVec } from '../../../../util/conversion.js'; +import { onlyConstInputSource, run } from '../expression.js'; + +import { d } from './af_matrix_vector_multiplication.cache.js'; +import { abstractFloatBinary } from './binary.js'; + +export const g = makeTestGroup(GPUTest); + +g.test('matrix_vector') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x * y, where x is a matrix and y is a vector +Accuracy: Correctly rounded +` + ) + .params(u => + u + .combine('inputSource', onlyConstInputSource) + .combine('cols', [2, 3, 4] as const) + .combine('rows', [2, 3, 4] as const) + ) + .fn(async t => { + const cols = t.params.cols; + const rows = t.params.rows; + const cases = await d.get(`mat${cols}x${rows}_vec${cols}`); + await run( + t, + abstractFloatBinary('*'), + [TypeMat(cols, rows, TypeAbstractFloat), TypeVec(cols, TypeAbstractFloat)], + TypeVec(rows, TypeAbstractFloat), + t.params, + cases + ); + }); + +g.test('vector_matrix') + .specURL('https://www.w3.org/TR/WGSL/#floating-point-evaluation') + .desc( + ` +Expression: x * y, where x is a vector and y is is a matrix +Accuracy: Correctly rounded +` + ) + .params(u => + u + .combine('inputSource', onlyConstInputSource) + .combine('cols', [2, 3, 4] as const) + .combine('rows', [2, 3, 4] as const) + ) + .fn(async t => { + const cols = t.params.cols; + const rows = t.params.rows; + const cases = await d.get(`vec${rows}_mat${cols}x${rows}`); + await run( + t, + abstractFloatBinary('*'), + [TypeVec(rows, TypeAbstractFloat), TypeMat(cols, rows, TypeAbstractFloat)], + TypeVec(cols, TypeAbstractFloat), + t.params, + cases + ); + }); diff --git a/src/webgpu/shader/execution/expression/case.ts b/src/webgpu/shader/execution/expression/case.ts index 1cbde7be754f..37e1d2a8f190 100644 --- a/src/webgpu/shader/execution/expression/case.ts +++ b/src/webgpu/shader/execution/expression/case.ts @@ -1,11 +1,13 @@ +import { crc32 } from '../../../../common/util/crc32.js'; import { ROArrayArray } from '../../../../common/util/types.js'; -import { ScalarBuilder, Value, Vector, i32, u32, abstractInt } from '../../../util/conversion.js'; +import { assert } from '../../../../common/util/util.js'; +import { abstractInt, i32, ScalarBuilder, u32, Value, Vector } from '../../../util/conversion.js'; import { - QuantizeFunc, cartesianProduct, + QuantizeFunc, quantizeToI32, - quantizeToU32, quantizeToI64, + quantizeToU32, } from '../../../util/math.js'; import { Expectation } from './expectation.js'; @@ -25,6 +27,47 @@ export type Case = { /** CaseList is a list of Cases */ export type CaseList = Array; +/** + * Filters a given set of Cases down to a target number of cases by + * randomly selecting which Cases to return. + * + * The selection algorithm is deterministic and stable for a case's + * inputs. + * + * This means that if a specific case is selected is not affected by the + * presence of other cases in the list, so in theory it is possible to create a + * pathological set of cases such that all or not of the cases are selected + * in spite of the target number. + * + * This is a trade-off from guaranteeing stability of the selected cases over + * small changes, so the target number of cases is more of a suggestion. It is + * still guaranteed that if you set n0 < n1, then the invocation with n0 will + * return at most the number of cases that n1 does, it just isn't guaranteed to + * be less. + * + * @param dis is a string provided for additional hashing information to avoid + * systemic bias in the selection process across different test + * suites. Specifically every Case with the same input values being + * included or skipped regardless of the operation that they are + * testing. This string should be something like the name of the case + * cache the values are for or the operation under test. + * @param n number of cases targeted be returned. Expected to be a positive + * integer. If equal or greater than the number of cases, then all the + * cases are returned. 0 is not allowed, since it is likely a + * programming error, because if the caller intentionally wants 0 + * items, they can just use []. + * @param cases list of Cases to be selected from. + */ +export function selectNCases(dis: string, n: number, cases: CaseList): CaseList { + assert(n > 0 && Math.round(n) === n, `n ${n} is expected to be a positive integer`); + const count = cases.length; + if (n >= count) { + return cases; + } + const dis_crc32 = crc32(dis); + return cases.filter(c => n * (0xffff_ffff / count) > (crc32(c.input.toString()) ^ dis_crc32)); +} + /** * A function that performs a binary operation on x and y, and returns the * expected result. diff --git a/src/webgpu/util/floating_point.ts b/src/webgpu/util/floating_point.ts index 31b90081bfe6..ea7bb838d4ca 100644 --- a/src/webgpu/util/floating_point.ts +++ b/src/webgpu/util/floating_point.ts @@ -5164,26 +5164,16 @@ class FPAbstractTraits extends FPTraits { public readonly mixIntervals = [this.mixImpreciseInterval, this.mixPreciseInterval]; public readonly modfInterval = this.modfIntervalImpl.bind(this); public readonly multiplicationInterval = this.multiplicationIntervalImpl.bind(this); - public readonly multiplicationMatrixMatrixInterval = this.unimplementedMatrixPairToMatrix.bind( - this, - 'multiplicationMatrixMatrixInterval' - ); - public readonly multiplicationMatrixScalarInterval = this.unimplementedMatrixScalarToMatrix.bind( - this, - 'multiplicationMatrixScalarInterval' - ); - public readonly multiplicationScalarMatrixInterval = this.unimplementedScalarMatrixToMatrix.bind( - this, - 'multiplicationScalarMatrixInterval' - ); - public readonly multiplicationMatrixVectorInterval = this.unimplementedMatrixVectorToVector.bind( - this, - 'multiplicationMatrixVectorInterval' - ); - public readonly multiplicationVectorMatrixInterval = this.unimplementedVectorMatrixToVector.bind( - this, - 'multiplicationVectorMatrixInterval' - ); + public readonly multiplicationMatrixMatrixInterval = + this.multiplicationMatrixMatrixIntervalImpl.bind(this); + public readonly multiplicationMatrixScalarInterval = + this.multiplicationMatrixScalarIntervalImpl.bind(this); + public readonly multiplicationScalarMatrixInterval = + this.multiplicationScalarMatrixIntervalImpl.bind(this); + public readonly multiplicationMatrixVectorInterval = + this.multiplicationMatrixVectorIntervalImpl.bind(this); + public readonly multiplicationVectorMatrixInterval = + this.multiplicationVectorMatrixIntervalImpl.bind(this); public readonly negationInterval = this.negationIntervalImpl.bind(this); public readonly normalizeInterval = this.unimplementedVectorToVector.bind( this,