Download cstack/src/l1_tensor.c from Snapkitty/flash-attention-rtl: direct link, hf CLI and curl.
- Browser
- Download file 5.23 kB
-
https://huggingface.co/Snapkitty/flash-attention-rtl/resolve/main/cstack/src/l1_tensor.c
- Command line
-
hf download hf://Snapkitty/flash-attention-rtl/cstack/src/l1_tensor.c
-
curl -L -o l1_tensor.c https://huggingface.co/Snapkitty/flash-attention-rtl/resolve/main/cstack/src/l1_tensor.c
5.23 kB
| cs_status tensor_new(tensor *t, size_t rank, const size_t *shape) | |
| { | |
| if (!t || !shape || rank == 0 || rank > CS_TENSOR_MAX_RANK) return CS_ERR_ARG; | |
| size_t size = 1; | |
| for (size_t i = 0; i < rank; i++) { | |
| if (shape[i] == 0) return CS_ERR_ARG; | |
| if (size > SIZE_MAX / shape[i]) return CS_ERR_NOMEM; | |
| size *= shape[i]; | |
| } | |
| if (size > SIZE_MAX / sizeof(gl_t)) return CS_ERR_NOMEM; | |
| gl_t *d = calloc(size, sizeof(gl_t)); | |
| if (!d) return CS_ERR_NOMEM; | |
| memset(t, 0, sizeof *t); | |
| t->rank = rank; | |
| memcpy(t->shape, shape, rank * sizeof(size_t)); | |
| t->d = d; | |
| t->size = size; | |
| return CS_OK; | |
| } | |
| void tensor_free(tensor *t) | |
| { | |
| if (!t) return; | |
| free(t->d); | |
| memset(t, 0, sizeof *t); | |
| } | |
| static int offset_of(const tensor *t, const size_t *idx, size_t *off) | |
| { | |
| size_t o = 0; | |
| for (size_t i = 0; i < t->rank; i++) { | |
| if (idx[i] >= t->shape[i]) return 0; | |
| o = o * t->shape[i] + idx[i]; | |
| } | |
| *off = o; | |
| return 1; | |
| } | |
| cs_status tensor_get(const tensor *t, const size_t *idx, gl_t *out) | |
| { | |
| size_t o; | |
| if (!t || !idx || !out || !t->d) return CS_ERR_ARG; | |
| if (!offset_of(t, idx, &o)) return CS_ERR_RANGE; | |
| *out = t->d[o]; | |
| return CS_OK; | |
| } | |
| cs_status tensor_set(tensor *t, const size_t *idx, gl_t v) | |
| { | |
| size_t o; | |
| if (!t || !idx || !t->d) return CS_ERR_ARG; | |
| if (!offset_of(t, idx, &o)) return CS_ERR_RANGE; | |
| t->d[o] = gl_reduce(v); | |
| return CS_OK; | |
| } | |
| static int same_shape(const tensor *a, const tensor *b) | |
| { | |
| return a->rank == b->rank && memcmp(a->shape, b->shape, a->rank * sizeof(size_t)) == 0; | |
| } | |
| static cs_status pointwise(const tensor *a, const tensor *b, tensor *out, int mul) | |
| { | |
| if (!a || !b || !out || !a->d || !b->d) return CS_ERR_ARG; | |
| if (!same_shape(a, b)) return CS_ERR_RANGE; | |
| tensor r; | |
| cs_status s = tensor_new(&r, a->rank, a->shape); | |
| if (s != CS_OK) return s; | |
| for (size_t i = 0; i < r.size; i++) | |
| r.d[i] = mul ? gl_mul(a->d[i], b->d[i]) : gl_add(a->d[i], b->d[i]); | |
| *out = r; | |
| return CS_OK; | |
| } | |
| cs_status tensor_add(const tensor *a, const tensor *b, tensor *out) { return pointwise(a, b, out, 0); } | |
| cs_status tensor_hadamard(const tensor *a, const tensor *b, tensor *out) { return pointwise(a, b, out, 1); } | |
| cs_status tensor_outer(const tensor *a, const tensor *b, tensor *out) | |
| { | |
| if (!a || !b || !out || !a->d || !b->d) return CS_ERR_ARG; | |
| if (a->rank + b->rank > CS_TENSOR_MAX_RANK) return CS_ERR_RANGE; | |
| size_t shape[CS_TENSOR_MAX_RANK]; | |
| memcpy(shape, a->shape, a->rank * sizeof(size_t)); | |
| memcpy(shape + a->rank, b->shape, b->rank * sizeof(size_t)); | |
| tensor r; | |
| cs_status s = tensor_new(&r, a->rank + b->rank, shape); | |
| if (s != CS_OK) return s; | |
| for (size_t i = 0; i < a->size; i++) | |
| for (size_t j = 0; j < b->size; j++) r.d[i * b->size + j] = gl_mul(a->d[i], b->d[j]); | |
| *out = r; | |
| return CS_OK; | |
| } | |
| cs_status tensor_contract(const tensor *a, size_t axis_a, const tensor *b, size_t axis_b, tensor *out) | |
| { | |
| if (!a || !b || !out || !a->d || !b->d) return CS_ERR_ARG; | |
| if (axis_a >= a->rank || axis_b >= b->rank) return CS_ERR_RANGE; | |
| if (a->shape[axis_a] != b->shape[axis_b]) return CS_ERR_RANGE; | |
| size_t rr = a->rank + b->rank - 2; | |
| if (rr == 0 || rr > CS_TENSOR_MAX_RANK) return CS_ERR_RANGE; | |
| size_t shape[CS_TENSOR_MAX_RANK], n = 0; | |
| for (size_t i = 0; i < a->rank; i++) if (i != axis_a) shape[n++] = a->shape[i]; | |
| for (size_t i = 0; i < b->rank; i++) if (i != axis_b) shape[n++] = b->shape[i]; | |
| tensor r; | |
| cs_status s = tensor_new(&r, rr, shape); | |
| if (s != CS_OK) return s; | |
| size_t ext = a->shape[axis_a]; | |
| size_t ia[CS_TENSOR_MAX_RANK], ib[CS_TENSOR_MAX_RANK], ir[CS_TENSOR_MAX_RANK] = {0}; | |
| for (size_t o = 0; o < r.size; o++) { | |
| /* decode o into the free indices of a then b */ | |
| size_t rem = o; | |
| for (size_t i = rr; i-- > 0;) { ir[i] = rem % r.shape[i]; rem /= r.shape[i]; } | |
| size_t p = 0; | |
| for (size_t i = 0; i < a->rank; i++) if (i != axis_a) ia[i] = ir[p++]; | |
| for (size_t i = 0; i < b->rank; i++) if (i != axis_b) ib[i] = ir[p++]; | |
| gl_t acc = 0; | |
| for (size_t k = 0; k < ext; k++) { | |
| ia[axis_a] = k; | |
| ib[axis_b] = k; | |
| size_t oa = 0, ob = 0; | |
| if (!offset_of(a, ia, &oa) || !offset_of(b, ib, &ob)) { | |
| tensor_free(&r); | |
| return CS_ERR_RANGE; | |
| } | |
| acc = gl_add(acc, gl_mul(a->d[oa], b->d[ob])); | |
| } | |
| r.d[o] = acc; | |
| } | |
| *out = r; | |
| return CS_OK; | |
| } | |
| cs_status tensor_from_pmat(const pmat *m, tensor *t) | |
| { | |
| if (!m || !t || !m->d) return CS_ERR_ARG; | |
| size_t shape[2] = {m->rows, m->cols}; | |
| cs_status s = tensor_new(t, 2, shape); | |
| if (s != CS_OK) return s; | |
| memcpy(t->d, m->d, t->size * sizeof(gl_t)); | |
| return CS_OK; | |
| } | |
| cs_status tensor_to_pmat(const tensor *t, pmat *m) | |
| { | |
| if (!t || !m || !t->d) return CS_ERR_ARG; | |
| if (t->rank != 2) return CS_ERR_RANGE; | |
| cs_status s = pmat_new(m, t->shape[0], t->shape[1]); | |
| if (s != CS_OK) return s; | |
| memcpy(m->d, t->d, t->size * sizeof(gl_t)); | |
| return CS_OK; | |
| } | |