/* * Copyright (c) 2001 Matteo Frigo * Copyright (c) 2001 Massachusetts Institute of Technology * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* $Id: tensor.c,v 1.9 2006-01-05 03:04:27 stevenj Exp $ */ #include "bench.h" #include bench_tensor *mktensor(int rnk) { bench_tensor *x; BENCH_ASSERT(rnk >= 0); x = (bench_tensor *)bench_malloc(sizeof(bench_tensor)); if (FINITE_RNK(rnk) && rnk > 0) x->dims = (bench_iodim *)bench_malloc(sizeof(bench_iodim) * rnk); else x->dims = 0; x->rnk = rnk; return x; } void tensor_destroy(bench_tensor *sz) { bench_free0(sz->dims); bench_free(sz); } int tensor_sz(const bench_tensor *sz) { int i, n = 1; if (!FINITE_RNK(sz->rnk)) return 0; for (i = 0; i < sz->rnk; ++i) n *= sz->dims[i].n; return n; } /* total order among bench_iodim's */ static int dimcmp(const bench_iodim *a, const bench_iodim *b) { if (b->is != a->is) return (b->is - a->is); /* shorter strides go later */ if (b->os != a->os) return (b->os - a->os); /* shorter strides go later */ return (int)(a->n - b->n); /* larger n's go later */ } bench_tensor *tensor_compress(const bench_tensor *sz) { int i, rnk; bench_tensor *x; BENCH_ASSERT(FINITE_RNK(sz->rnk)); for (i = rnk = 0; i < sz->rnk; ++i) { BENCH_ASSERT(sz->dims[i].n > 0); if (sz->dims[i].n != 1) ++rnk; } x = mktensor(rnk); for (i = rnk = 0; i < sz->rnk; ++i) { if (sz->dims[i].n != 1) x->dims[rnk++] = sz->dims[i]; } if (rnk) { /* God knows how qsort() behaves if n==0 */ qsort(x->dims, (size_t)x->rnk, sizeof(bench_iodim), (int (*)(const void *, const void *))dimcmp); } return x; } int tensor_unitstridep(bench_tensor *t) { BENCH_ASSERT(FINITE_RNK(t->rnk)); return (t->rnk == 0 || (t->dims[t->rnk - 1].is == 1 && t->dims[t->rnk - 1].os == 1)); } /* detect screwy real padded rowmajor... ugh */ int tensor_real_rowmajorp(bench_tensor *t, int sign, int in_place) { int i; BENCH_ASSERT(FINITE_RNK(t->rnk)); i = t->rnk - 1; if (--i >= 0) { bench_iodim *d = t->dims + i; if (sign < 0) { if (d[0].is != d[1].is * (in_place ? 2*(d[1].n/2 + 1) : d[1].n)) return 0; if (d[0].os != d[1].os * (d[1].n/2 + 1)) return 0; } else { if (d[0].is != d[1].is * (d[1].n/2 + 1)) return 0; if (d[0].os != d[1].os * (in_place ? 2*(d[1].n/2 + 1) : d[1].n)) return 0; } } while (--i >= 0) { bench_iodim *d = t->dims + i; if (d[0].is != d[1].is * d[1].n) return 0; if (d[0].os != d[1].os * d[1].n) return 0; } return 1; } int tensor_rowmajorp(bench_tensor *t) { int i; BENCH_ASSERT(FINITE_RNK(t->rnk)); i = t->rnk - 1; while (--i >= 0) { bench_iodim *d = t->dims + i; if (d[0].is != d[1].is * d[1].n) return 0; if (d[0].os != d[1].os * d[1].n) return 0; } return 1; } static void dimcpy(bench_iodim *dst, const bench_iodim *src, int rnk) { int i; if (FINITE_RNK(rnk)) for (i = 0; i < rnk; ++i) dst[i] = src[i]; } bench_tensor *tensor_append(const bench_tensor *a, const bench_tensor *b) { if (!FINITE_RNK(a->rnk) || !FINITE_RNK(b->rnk)) { return mktensor(RNK_MINFTY); } else { bench_tensor *x = mktensor(a->rnk + b->rnk); dimcpy(x->dims, a->dims, a->rnk); dimcpy(x->dims + a->rnk, b->dims, b->rnk); return x; } } static int imax(int a, int b) { return (a > b) ? a : b; } static int imin(int a, int b) { return (a < b) ? a : b; } #define DEFBOUNDS(name, xs) \ void name(bench_tensor *t, int *lbp, int *ubp) \ { \ int lb = 0; \ int ub = 1; \ int i; \ \ BENCH_ASSERT(FINITE_RNK(t->rnk)); \ \ for (i = 0; i < t->rnk; ++i) { \ bench_iodim *d = t->dims + i; \ int n = d->n; \ int s = d->xs; \ lb = imin(lb, lb + s * (n - 1)); \ ub = imax(ub, ub + s * (n - 1)); \ } \ \ *lbp = lb; \ *ubp = ub; \ } DEFBOUNDS(tensor_ibounds, is) DEFBOUNDS(tensor_obounds, os) bench_tensor *tensor_copy(const bench_tensor *sz) { bench_tensor *x = mktensor(sz->rnk); dimcpy(x->dims, sz->dims, sz->rnk); return x; } /* Like tensor_copy, but copy only rnk dimensions starting with start_dim. */ bench_tensor *tensor_copy_sub(const bench_tensor *sz, int start_dim, int rnk) { bench_tensor *x; BENCH_ASSERT(FINITE_RNK(sz->rnk) && start_dim + rnk <= sz->rnk); x = mktensor(rnk); dimcpy(x->dims, sz->dims + start_dim, rnk); return x; } bench_tensor *tensor_copy_swapio(const bench_tensor *sz) { bench_tensor *x = tensor_copy(sz); int i; if (FINITE_RNK(x->rnk)) for (i = 0; i < x->rnk; ++i) { int s; s = x->dims[i].is; x->dims[i].is = x->dims[i].os; x->dims[i].os = s; } return x; }