18static int lmmc_tensor_nd_contraction_inputs_are_valid(
21 if (!lmmc_tensor_nd_descriptor_is_valid(a)) {
24 if (!lmmc_tensor_nd_descriptor_is_valid(b)) {
30static int lmmc_tensor_nd_contraction_alias_is_valid(
42static int lmmc_tensor_nd_contraction_axes_are_valid(
51 if (contraction->
naxes == 0) {
54 if (contraction->
axes_a == NULL) {
57 return contraction->
axes_b != NULL;
64 if (!lmmc_tensor_nd_contraction_inputs_are_valid(a, b, out)) {
67 if (!lmmc_tensor_nd_contraction_alias_is_valid(a, b, out)) {
70 if (!lmmc_tensor_nd_contraction_axes_are_valid(a, b, contraction)) {
76static size_t lmmc_tensor_nd_free_axes(
size_t ndim,
const int* contracted,
size_t* axes) {
79 for (
size_t i = 0; i < ndim; ++i) {
93 for (
size_t i = 0; i < contraction->
naxes; ++i) {
94 const size_t axis_a = contraction->
axes_a[i];
95 const size_t axis_b = contraction->
axes_b[i];
96 if (axis_a >= a->
ndim || axis_b >= b->
ndim) {
99 if (a_contracted[axis_a] || b_contracted[axis_b]) {
102 if (a->
dims[axis_a] != b->
dims[axis_b] ||
108 a_contracted[axis_a] = 1;
109 b_contracted[axis_b] = 1;
115 *out_ndim = free_count == 0 ? 1 : free_count;
121 for (
size_t i = 0; i < contraction->
n_a_free; ++i) {
124 for (
size_t i = 0; i < contraction->
n_b_free; ++i) {
127 if (free_count == 0) {
133static size_t lmmc_tensor_nd_contracted_offset(
135 const size_t* out_idx,
const size_t* contracted_axes,
size_t naxes,
136 const size_t* contract_idx) {
138 for (
size_t i = 0; i < n_free; ++i) {
139 full_idx[free_axes[i]] = out_idx[i];
141 for (
size_t i = 0; i < naxes; ++i) {
142 full_idx[contracted_axes[i]] = contract_idx[i];
144 return lmmc_tensor_nd_offset(tensor->
ndim, tensor->
strides, full_idx);
147static void lmmc_tensor_nd_next_contracted_index(
149 size_t* contract_idx) {
150 size_t ci = contraction->
naxes;
155 if (contract_idx[ci] < a->
dims[contraction->
axes_a[ci]]) {
158 contract_idx[ci] = 0;
162static void lmmc_tensor_nd_contract_element(
168 for (
size_t k = 0; k < contract_size; ++k) {
169 const size_t a_offset = lmmc_tensor_nd_contracted_offset(
171 contraction->
axes_a, contraction->
naxes, contract_idx);
172 const size_t b_offset = lmmc_tensor_nd_contracted_offset(
175 contraction->
naxes, contract_idx);
176 lmmc_tensor_nd_add_product(sum, &a->
data[a_offset], &b->
data[b_offset]);
177 lmmc_tensor_nd_next_contracted_index(a, contraction, contract_idx);
181static void lmmc_tensor_nd_execute_contraction(
188 lmmc_tensor_nd_contract_element(
189 a, b, contraction, contraction->
contract_size, out_idx, &sum);
190 const size_t offset = lmmc_tensor_nd_offset(out->
ndim, out->
strides, out_idx);
193 }
while (lmmc_tensor_nd_next_index(out->
ndim, out->
dims, out_idx));
197 const size_t* axes_a,
const size_t* axes_b,
size_t naxes,
lmmc_tensor_nd_t* out) {
204 contraction.
naxes = naxes;
205 contraction.
axes_a = axes_a;
206 contraction.
axes_b = axes_b;
207 lmmc_status_t st = lmmc_tensor_nd_validate_contraction(a, b, &contraction, out);
209 st = lmmc_tensor_nd_contraction_shape(a, b, &contraction, &out_ndim, out_dims);
222 st = lmmc_tensor_nd_allocate_result(out_ndim, out_dims, &result);
226 lmmc_tensor_nd_execute_contraction(a, b, &contraction, &result);
234 if (!lmmc_tensor_nd_descriptor_is_valid(t) ||
235 !lmmc_mat_descriptor_is_valid(mat) || out == NULL) {
247static void lmmc_tensor_nd_mode_product_element(
250 const size_t j_dim = t->
dims[mode];
252 for (
size_t i = 0; i < j_dim; ++i) {
254 size_t src_offset = 0;
255 for (
size_t d = 0; d < t->
ndim; ++d) {
257 src_offset += i * t->
strides[d];
259 src_offset += out_idx[d] * t->
strides[d];
262 lmmc_tensor_nd_add_product(
263 sum, &mat->
data[out_idx[mode] * mat->
stride + i], &t->
data[src_offset]);
267static void lmmc_tensor_nd_execute_mode_product(
275 lmmc_tensor_nd_mode_product_element(t, mat, mode, out_idx, &sum);
276 const size_t offset = lmmc_tensor_nd_offset(out->
ndim, out->
strides, out_idx);
279 }
while (lmmc_tensor_nd_next_index(out->
ndim, out->
dims, out_idx));
287 lmmc_status_t st = lmmc_tensor_nd_validate_mode_product(t, mat, mode, out);
291 for (
size_t i = 0; i < t->
ndim; ++i) {
292 out_dims[i] = i == mode ? mat->
rows : t->
dims[i];
298 st = lmmc_tensor_nd_allocate_result(t->
ndim, out_dims, &result);
302 lmmc_tensor_nd_execute_mode_product(t, mat, mode, &result);
#define LMMC_REAL_CLEAR(x)
释放一个 lmmc_real_t 变量(POD 类型为空操作)。
#define LMMC_REAL_INIT(x)
初始化一个 lmmc_real_t 变量(POD 类型为空操作)。
double lmmc_real_t
Public and internal LMMC real type.
#define LMMC_REAL_SET(dst, src)
将一个 lmmc_real_t 赋值到另一个:*dst = *src 。
#define LMMC_REAL_SET_D(dst, dbl)
将一个 double 字面量赋值到 lmmc_real_t 。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_INVALID_ARGUMENT
lmmc_status_t lmmc_tensor_nd_mode_n_product(const lmmc_tensor_nd_t *t, const lmmc_mat_t *mat, size_t mode, lmmc_tensor_nd_t *out)
模-n 乘积:沿指定模与矩阵收缩.
lmmc_status_t lmmc_tensor_nd_contract(const lmmc_tensor_nd_t *a, const lmmc_tensor_nd_t *b, const size_t *axes_a, const size_t *axes_b, size_t naxes, lmmc_tensor_nd_t *out)
张量收缩:沿匹配轴对求和.
#define LMMC_TENSOR_MAX_NDIM
支持的最大张量维度.
size_t dims[LMMC_TENSOR_MAX_NDIM]
size_t strides[LMMC_TENSOR_MAX_NDIM]
size_t b_free_axes[LMMC_TENSOR_MAX_NDIM]
size_t a_free_axes[LMMC_TENSOR_MAX_NDIM]