2021/06/11

实现一个任意1-4维的矩阵类 Tensor

完成这个实验课题目能让我们懂得高维到1维展开的一般方法,和帮助我们更好地理解和完成本周的理论课作业。

请先阅读主程序,然后实现函数:

double & Tensor_get(int dimensions, const int sizes[], const double data[], int x0, int x1, int x2, int x3)

注意

这个类的对象的构造函数指定了tensor的维数和每维的大小
成员函数get的前4行保证给定的每维的维度和大小都不越界
EXAMPLE INPUT

0 0

2 1

0 2

2 3 4

2 3 0

1 1 2

1 1 3 1

1 3 3 0

1 3 4 40

EXAMPLE OUTPUT

0

21

2

234

230

112

1131

1330

1344

主程序 (不能修改)

#include "source.cpp"

#include <iostream>
using namespace std;

void _assert(bool valid, const char err_msg[]) {
    if (valid) return;
    cout << err_msg << endl;
    exit(1);
}

class Tensor
{
private:
    double * data;
    int sizes[4];
    int dimensions;

public:
    Tensor(int size0, int size1=-1, int size2=-1, int size3=-1) {
        _assert(size0 > 0, "第0维大小必须大于0");
        if (size1 != -1) _assert(size1 > 0, "第1维大小必须大于0");
        if (size2 != -1) _assert(size2 > 0, "第2维大小必须大于0");
        if (size3 != -1) _assert(size3 > 0, "第3维大小必须大于0");

        this->dimensions = 1;
        this->sizes[0] = size0;
        this->sizes[1] = this->sizes[2] = this->sizes[3] = 1;
        if (size1 != -1) {
            this->dimensions = 2;
            this->sizes[1] = size1;
        }
        if (size2 != -1) {
            this->dimensions = 3;
            this->sizes[2] = size2;
        }
        if (size3 != -1) {
            this->dimensions = 4;
            this->sizes[3] = size3;
        }

        int totel_size = this->numel();
        this->data = new double[totel_size];
        for (int i = 0; i < totel_size; ++ i)
            this->data[i] = 0;
    }

    int numel() { // number of elements
        return this->sizes[0] * this->sizes[1] * this->sizes[2] * this->sizes[3];
    }

    void fill(double value) {
        for (int i = 0; i < this->numel(); ++ i)
            this->data[i] = value;
    }

    ~Tensor() {
        delete [] this->data;
    }

    double & get(int x0, int x1=-1, int x2=-1, int x3=-1) {
        // 检查有否越界
        _assert(x0 >= 0 && x0 < this->sizes[0], "第0维越界");
        _assert((this->dimensions < 2 && x1 == -1) || (x1 >= 0 && x1 < this->sizes[1]), "第1维越界");
        _assert((this->dimensions < 3 && x2 == -1) || (x2 >= 0 && x2 < this->sizes[2]), "第2维越界");
        _assert((this->dimensions < 4 && x3 == -1) || (x3 >= 0 && x3 < this->sizes[3]), "第3维越界");

        return Tensor_get(this->dimensions, this->sizes, this->data, x0, x1, x2, x3);
    }

};

int main() {
    // 测试1
    Tensor t1(3, 4);
    for (int i = 0; i < 3; ++ i) {
        for (int j = 0; j < 4; ++ j) {
            t1.get(i, j) = i * 10 + j;
        }
    }
    for (int i = 0; i < 3; ++ i) {
        int x0, x1;
        cin >> x0 >> x1;
        cout << t1.get(x0, x1) << endl;
    }
    cout << endl;

    // 测试2
    Tensor t2(3, 4, 5);
    for (int i = 0; i < 3; ++ i) {
        for (int j = 0; j < 4; ++ j) {
            for (int k = 0; k < 5; ++ k) {
                t2.get(i, j, k) = i * 100 + j * 10 + k;
            }
        }
    }
    for (int i = 0; i < 3; ++ i) {
        int x0, x1, x2;
        cin >> x0 >> x1 >> x2;
        cout << t2.get(x0, x1, x2) << endl;
    }
    cout << endl;
    
    // 测试3
    Tensor t3(3, 4, 5, 6);
    for (int i = 0; i < 3; ++ i) {
        for (int j = 0; j < 4; ++ j) {
            for (int k = 0; k < 5; ++ k) {
                for (int l = 0; l < 6; ++ l) {
                    t3.get(i, j, k, l) = i * 1000 + j * 100 + k * 10 + l;
                }
            }
        }
    }
    for (int i = 0; i < 3; ++ i) {
        int x0, x1, x2, x3;
        cin >> x0 >> x1 >> x2 >> x3;
        cout << t3.get(x0, x1, x2, x3) << endl;
    }
}

参考答案

double & Tensor_get(int dimensions, const int sizes[], double data[], int x0, int x1, int x2, int x3){
    int index=0;
    if(dimensions==1) index=x0;
    else if(dimensions==2) index=x0*sizes[1]+x1;
    else if(dimensions==3) index=x0*sizes[2]*sizes[1]+x1*sizes[2]+x2;
    else if(dimensions==4) index=x0*sizes[3]*sizes[2]*sizes[1]+x1*sizes[3]*sizes[2]+x2*sizes[3]+x3;
    return data[index];
}
上一篇: 15.1 (C++) 下一篇: C.1(C++)
支持 makedown语法