Download cstack/tests/test_l1_uac.c from Snapkitty/flash-attention-rtl: direct link, hf CLI and curl.
- Browser
- Download file 9.21 kB
-
https://huggingface.co/Snapkitty/flash-attention-rtl/resolve/main/cstack/tests/test_l1_uac.c
- Command line
-
hf download hf://Snapkitty/flash-attention-rtl/cstack/tests/test_l1_uac.c
-
curl -L -o test_l1_uac.c https://huggingface.co/Snapkitty/flash-attention-rtl/resolve/main/cstack/tests/test_l1_uac.c
9.21 kB
| __extension__ typedef unsigned __int128 u128; | |
| static uint64_t rng_state = 0x123456789abcdef1ull; | |
| static uint64_t rnd(void) | |
| { | |
| rng_state ^= rng_state << 13; rng_state ^= rng_state >> 7; rng_state ^= rng_state << 17; | |
| return rng_state; | |
| } | |
| static gl_t rnd_gl(void) { return gl_reduce(rnd()); } | |
| static void fill(pmat *m) { for (size_t i = 0; i < m->rows * m->cols; i++) m->d[i] = rnd_gl(); } | |
| TEST_MAIN_BEGIN("l1 uac") | |
| CHECK_EQ_STATUS(gl_selftest(), CS_OK); | |
| /* edge values vs a __int128 reference */ | |
| const gl_t edges[] = {0, 1, 2, 0xFFFFFFFFull, 0x100000000ull, 0x100000001ull, | |
| GL_P - 2, GL_P - 1, GL_P / 2, GL_P / 2 + 1, 0xFFFFFFFE00000001ull}; | |
| for (size_t i = 0; i < sizeof edges / sizeof edges[0]; i++) | |
| for (size_t j = 0; j < sizeof edges / sizeof edges[0]; j++) { | |
| gl_t a = edges[i], b = edges[j]; | |
| CHECK(gl_mul(a, b) == (gl_t)(((u128)a * b) % GL_P)); | |
| CHECK(gl_add(a, b) == (gl_t)(((u128)a + b) % GL_P)); | |
| CHECK(gl_sub(a, b) == (gl_t)(((u128)a + GL_P - b) % GL_P)); | |
| } | |
| /* random vs reference */ | |
| int bad = 0; | |
| for (int i = 0; i < 200000; i++) { | |
| gl_t a = rnd_gl(), b = rnd_gl(); | |
| if (gl_mul(a, b) != (gl_t)(((u128)a * b) % GL_P)) bad++; | |
| if (gl_add(a, b) != (gl_t)(((u128)a + b) % GL_P)) bad++; | |
| if (gl_sub(a, b) != (gl_t)(((u128)a + GL_P - b) % GL_P)) bad++; | |
| if (gl_add(a, gl_neg(a)) != 0) bad++; | |
| } | |
| CHECK(bad == 0); | |
| /* field axioms on random triples */ | |
| bad = 0; | |
| for (int i = 0; i < 20000; i++) { | |
| gl_t a = rnd_gl(), b = rnd_gl(), c = rnd_gl(); | |
| if (gl_mul(a, gl_add(b, c)) != gl_add(gl_mul(a, b), gl_mul(a, c))) bad++; /* distributive */ | |
| if (gl_mul(gl_mul(a, b), c) != gl_mul(a, gl_mul(b, c))) bad++; /* associative */ | |
| gl_t inv; | |
| if (a != 0 && (gl_inv(a, &inv) != CS_OK || gl_mul(a, inv) != 1)) bad++; | |
| } | |
| CHECK(bad == 0); | |
| gl_t q; | |
| CHECK_EQ_STATUS(gl_inv(0, &q), CS_ERR_SINGULAR); | |
| CHECK_EQ_STATUS(gl_div(5, 0, &q), CS_ERR_SINGULAR); | |
| CHECK_EQ_STATUS(gl_div(10, 2, &q), CS_OK); | |
| CHECK(q == 5); | |
| CHECK(gl_pow(3, 0) == 1 && gl_pow(0, 5) == 0 && gl_pow(GL_P - 1, 3) == GL_P - 1); | |
| /* matrices */ | |
| pmat a, b, c, d, id; | |
| CHECK_EQ_STATUS(pmat_new(&a, 0, 3), CS_ERR_ARG); | |
| CHECK_EQ_STATUS(pmat_new(&a, (size_t)-1, 8), CS_ERR_NOMEM); | |
| CHECK_EQ_STATUS(pmat_new(&a, 3, 4), CS_OK); | |
| CHECK_EQ_STATUS(pmat_new(&b, 4, 2), CS_OK); | |
| fill(&a); fill(&b); | |
| CHECK_EQ_STATUS(pmat_mul(&a, &a, &c), CS_ERR_RANGE); /* 3x4 * 3x4 */ | |
| CHECK_EQ_STATUS(pmat_mul(&a, &b, &c), CS_OK); | |
| CHECK(c.rows == 3 && c.cols == 2); | |
| gl_t ref = 0; | |
| for (size_t k = 0; k < 4; k++) ref = gl_add(ref, gl_mul(pmat_get(&a, 1, k), pmat_get(&b, k, 1))); | |
| CHECK(pmat_get(&c, 1, 1) == ref); | |
| /* (AB)^T = B^T A^T */ | |
| pmat abt, at, bt, btat; | |
| CHECK_EQ_STATUS(pmat_transpose(&c, &abt), CS_OK); | |
| CHECK_EQ_STATUS(pmat_transpose(&a, &at), CS_OK); | |
| CHECK_EQ_STATUS(pmat_transpose(&b, &bt), CS_OK); | |
| CHECK_EQ_STATUS(pmat_mul(&bt, &at, &btat), CS_OK); | |
| CHECK(pmat_equal(&abt, &btat)); | |
| pmat_free(&abt); pmat_free(&at); pmat_free(&bt); pmat_free(&btat); | |
| /* add / sub / scale */ | |
| pmat a2, s1, s2; | |
| CHECK_EQ_STATUS(pmat_add(&a, &a, &a2), CS_OK); | |
| CHECK_EQ_STATUS(pmat_scale(&a, 2, &s1), CS_OK); | |
| CHECK(pmat_equal(&a2, &s1)); | |
| CHECK_EQ_STATUS(pmat_sub(&a2, &a, &s2), CS_OK); | |
| CHECK(pmat_equal(&s2, &a)); | |
| CHECK_EQ_STATUS(pmat_add(&a, &b, &d), CS_ERR_RANGE); | |
| pmat_free(&a2); pmat_free(&s1); pmat_free(&s2); | |
| pmat_free(&a); pmat_free(&b); pmat_free(&c); | |
| /* inverse / determinant */ | |
| int inv_bad = 0, det_bad = 0; | |
| for (int trial = 0; trial < 40; trial++) { | |
| size_t n = 1 + (size_t)(rnd() % 6); | |
| pmat m, mi, prod, m2, prod2; | |
| pmat_new(&m, n, n); | |
| fill(&m); | |
| gl_t det; | |
| CHECK_EQ_STATUS(pmat_det(&m, &det), CS_OK); | |
| if (pmat_inverse(&m, &mi) == CS_OK) { | |
| pmat_mul(&m, &mi, &prod); | |
| pmat_identity(&id, n); | |
| if (!pmat_equal(&prod, &id)) inv_bad++; | |
| pmat_mul(&mi, &m, &prod2); | |
| if (!pmat_equal(&prod2, &id)) inv_bad++; | |
| /* det(A) * det(A^-1) = 1 */ | |
| gl_t det_i; | |
| pmat_det(&mi, &det_i); | |
| if (gl_mul(det, det_i) != 1) det_bad++; | |
| pmat_free(&mi); pmat_free(&prod); pmat_free(&prod2); pmat_free(&id); | |
| } | |
| /* det(A^T) = det(A) */ | |
| pmat_transpose(&m, &m2); | |
| gl_t det_t; | |
| pmat_det(&m2, &det_t); | |
| if (det_t != det) det_bad++; | |
| pmat_free(&m); pmat_free(&m2); | |
| } | |
| CHECK(inv_bad == 0 && det_bad == 0); | |
| /* known 2x2: [[1,2],[3,4]] det = -2, inverse = [[-2,1],[3/2,-1/2]] */ | |
| pmat k, ki; | |
| pmat_new(&k, 2, 2); | |
| pmat_set(&k, 0, 0, 1); pmat_set(&k, 0, 1, 2); pmat_set(&k, 1, 0, 3); pmat_set(&k, 1, 1, 4); | |
| gl_t kd; | |
| CHECK_EQ_STATUS(pmat_det(&k, &kd), CS_OK); | |
| CHECK(kd == gl_neg(2)); | |
| CHECK_EQ_STATUS(pmat_inverse(&k, &ki), CS_OK); | |
| gl_t half; | |
| gl_inv(2, &half); | |
| CHECK(pmat_get(&ki, 0, 0) == gl_neg(2) && pmat_get(&ki, 0, 1) == 1); | |
| CHECK(pmat_get(&ki, 1, 0) == gl_mul(3, half) && pmat_get(&ki, 1, 1) == gl_neg(half)); | |
| pmat_free(&ki); | |
| /* singular: second row = 2 * first row */ | |
| pmat_set(&k, 1, 0, 2); pmat_set(&k, 1, 1, 4); | |
| CHECK_EQ_STATUS(pmat_inverse(&k, &ki), CS_ERR_SINGULAR); | |
| CHECK_EQ_STATUS(pmat_det(&k, &kd), CS_OK); | |
| CHECK(kd == 0); | |
| pmat_free(&k); | |
| pmat rect; | |
| pmat_new(&rect, 2, 3); | |
| CHECK_EQ_STATUS(pmat_inverse(&rect, &ki), CS_ERR_RANGE); | |
| pmat_free(&rect); | |
| /* tensors */ | |
| size_t sh2[2] = {3, 4}, sh3[3] = {2, 3, 4}; | |
| tensor t; | |
| CHECK_EQ_STATUS(tensor_new(&t, 0, sh2), CS_ERR_ARG); | |
| CHECK_EQ_STATUS(tensor_new(&t, CS_TENSOR_MAX_RANK + 1, sh3), CS_ERR_ARG); | |
| size_t zero_shape[2] = {3, 0}; | |
| CHECK_EQ_STATUS(tensor_new(&t, 2, zero_shape), CS_ERR_ARG); | |
| CHECK_EQ_STATUS(tensor_new(&t, 3, sh3), CS_OK); | |
| size_t idx[3] = {1, 2, 3}; | |
| CHECK_EQ_STATUS(tensor_set(&t, idx, GL_P + 5), CS_OK); /* reduced on set */ | |
| gl_t v; | |
| CHECK_EQ_STATUS(tensor_get(&t, idx, &v), CS_OK); | |
| CHECK(v == 5); | |
| CHECK(t.d[1 * 12 + 2 * 4 + 3] == 5); /* row-major layout */ | |
| idx[1] = 3; | |
| CHECK_EQ_STATUS(tensor_get(&t, idx, &v), CS_ERR_RANGE); | |
| tensor_free(&t); | |
| /* contraction of rank-2 tensors == matrix multiplication */ | |
| pmat ma, mb, mc, mc2; | |
| pmat_new(&ma, 3, 5); pmat_new(&mb, 5, 2); | |
| fill(&ma); fill(&mb); | |
| tensor ta, tb, tc; | |
| tensor_from_pmat(&ma, &ta); | |
| tensor_from_pmat(&mb, &tb); | |
| CHECK_EQ_STATUS(tensor_contract(&ta, 1, &tb, 0, &tc), CS_OK); | |
| CHECK_EQ_STATUS(tensor_to_pmat(&tc, &mc), CS_OK); | |
| CHECK_EQ_STATUS(pmat_mul(&ma, &mb, &mc2), CS_OK); | |
| CHECK(pmat_equal(&mc, &mc2)); | |
| CHECK_EQ_STATUS(tensor_contract(&ta, 0, &tb, 0, &tc), CS_ERR_RANGE); /* 3 != 5 */ | |
| CHECK_EQ_STATUS(tensor_contract(&ta, 2, &tb, 0, &tc), CS_ERR_RANGE); /* bad axis */ | |
| tensor_free(&tc); | |
| /* contracting over a different axis pair = multiplication by a transpose */ | |
| pmat mat_t; | |
| pmat_transpose(&mb, &mat_t); /* 2x5 */ | |
| tensor tbt; | |
| tensor_from_pmat(&mat_t, &tbt); | |
| CHECK_EQ_STATUS(tensor_contract(&ta, 1, &tbt, 1, &tc), CS_OK); | |
| pmat mc3; | |
| tensor_to_pmat(&tc, &mc3); | |
| CHECK(pmat_equal(&mc3, &mc2)); | |
| pmat_free(&mc3); pmat_free(&mat_t); tensor_free(&tbt); tensor_free(&tc); | |
| /* outer product, hadamard, add */ | |
| size_t len3[1] = {3}, len2[1] = {2}; | |
| tensor x, y, o; | |
| tensor_new(&x, 1, len3); tensor_new(&y, 1, len2); | |
| for (size_t i = 0; i < 3; i++) x.d[i] = rnd_gl(); | |
| for (size_t i = 0; i < 2; i++) y.d[i] = rnd_gl(); | |
| CHECK_EQ_STATUS(tensor_outer(&x, &y, &o), CS_OK); | |
| CHECK(o.rank == 2 && o.shape[0] == 3 && o.shape[1] == 2); | |
| size_t oi[2] = {2, 1}; | |
| tensor_get(&o, oi, &v); | |
| CHECK(v == gl_mul(x.d[2], y.d[1])); | |
| /* contracting an outer product with a vector recovers a scaled vector */ | |
| tensor w, z; | |
| tensor_new(&w, 1, len2); | |
| w.d[0] = 1; w.d[1] = 0; | |
| CHECK_EQ_STATUS(tensor_contract(&o, 1, &w, 0, &z), CS_OK); | |
| CHECK(z.rank == 1 && z.d[0] == gl_mul(x.d[0], y.d[0]) && z.d[2] == gl_mul(x.d[2], y.d[0])); | |
| CHECK_EQ_STATUS(tensor_hadamard(&x, &y, &z), CS_ERR_RANGE); | |
| tensor x2, h; | |
| CHECK_EQ_STATUS(tensor_add(&x, &x, &x2), CS_OK); | |
| CHECK_EQ_STATUS(tensor_hadamard(&x, &x, &h), CS_OK); | |
| CHECK(x2.d[1] == gl_add(x.d[1], x.d[1]) && h.d[1] == gl_mul(x.d[1], x.d[1])); | |
| tensor big_a, big_b, big_o; | |
| size_t s22[2] = {1, 1}, s222[3] = {1, 1, 1}; | |
| tensor_new(&big_a, 2, s22); tensor_new(&big_b, 3, s222); | |
| CHECK_EQ_STATUS(tensor_outer(&big_a, &big_b, &big_o), CS_ERR_RANGE); /* rank 5 > max */ | |
| tensor_free(&big_a); tensor_free(&big_b); | |
| tensor_free(&x); tensor_free(&y); tensor_free(&o); tensor_free(&w); tensor_free(&z); | |
| tensor_free(&x2); tensor_free(&h); | |
| tensor_free(&ta); tensor_free(&tb); | |
| pmat_free(&ma); pmat_free(&mb); pmat_free(&mc); pmat_free(&mc2); | |
| TEST_MAIN_END | |