Transpose.cpp 5.21 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* NiuTrans.Tensor - an open-source tensor library
 * Copyright (C) 2017, Natural Language Processing Lab, Northestern University.
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
17

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
/*
 * $Created by: XIAO Tong (email: xiaotong@mail.neu.edu.cn) 2018-07-28
 * It is extreamly hot these days and i cannot sleep well. Fortunately we had 
 * good lunch of Steamed Cold Noodles. This made me feel much better!
 */

#include "Transpose.h"
#include "Merge.h"
#include "../../XUtility.h"
#include "../../XName.h"

namespace nts { // namespace nts(NiuTrans.Tensor)

/*
tensor transposition of dimensions i and j
b = transposed(a) 

For a input tensor a, we tranpose the dimensions i and j of it.
E.g., let a be a tensor of size x * y * z, i = 0, j = 2, 
then the output will be a tensor of size z * y * x.

>> a - the input tensor
>> b - the output tensor by transpose tensor a with specified dimensions i and j
>> i - the transposed dimension
>> j - the transposed dimension
*/
void _Transpose(const XTensor * a, XTensor * b, const int i, const int j)
{
    CheckNTErrors(a && b, "Empty tensors");
    CheckNTErrors(a->order == b->order, "Wrong tensor orders");
    CheckNTErrors(a->unitNum == b->unitNum && a->unitSize == b->unitSize, "Wrong tensor sizes");
    CheckNTErrors(a->order > i && i >= 0, "index of dimension is out of scope!");
    CheckNTErrors(a->order > j && j >= 0, "index of dimension is out of scope!");

    for(int k = 0; k < a->order; k++){
        if(k == i){
            CheckNTErrors(a->dimSize[k] == b->dimSize[j], "Wrong dimension size in transposition");
        }
        else if(k == j){
            CheckNTErrors(a->dimSize[k] == b->dimSize[i], "Wrong dimension size in transposition");
        }
        else{
            CheckNTErrors(a->dimSize[k] == b->dimSize[k], "Wrong dimension size in transposition");
        }
    }

    if(i == j){
        XMemCopy(b->data, b->devID, a->data, a->devID, b->unitNum * b->unitSize);
    }
    else{
        int I = MIN(i, j);
        int J = MAX(i, j);
        int * dims = new int[a->order + 1];

        for(int k = 0; k <= J; k++)
            dims[k] = a->dimSize[k];
        dims[J + 1] = -1;
        for(int k = J + 1; k < a->order; k++)
            dims[k + 1] = a->dimSize[k];

        /* reshape tensor a form (..., n_I, ..., n_J, ...) => (..., n_I, ..., n_J, 1, ...)*/
        XTensor * aTMP =  new XTensor(a->order + 1, dims, a->dataType, a->denseRatio, a->devID, a->mem);
        aTMP->data = a->data;

        for(int k = 0; k < I; k++)
            dims[k] = a->dimSize[k];
        for(int k = I + 1; k <= J; k++)
            dims[k - 1] = a->dimSize[k];
        dims[J] = a->dimSize[I];
        for(int k = J + 1; k < a->order; k++)
            dims[k] = a->dimSize[k];

        /* reshape tensor b form (..., m_I, ..., m_J, ...) => (..., m_J, m_I, ...) */
        b->Reshape(b->order, dims);

        /* tensor (..., n_I, ..., n_J, 1, ...) => tensor (..., m_J, m_I, ...) */
        _Merge(aTMP, b, J + 1, I);

        memcpy(dims, a->dimSize, sizeof(int) * a->order);
        dims[I] = a->dimSize[J];
        dims[J] = a->dimSize[I];

        /* reshape tensor b form (..., m_J, m_I, ...) => (..., m_J, ..., m_I, ...) =>  */
        b->Reshape(b->order, dims);

        aTMP->data = NULL;
        delete[] dims;
        delete aTMP;
    }
}

/*
xiaotong committed
110
tensor transposition of dimensions i and j (return an XTensor structure).
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
make a new tensor to keep the result and return it.
b = transposed(a)

For a input tensor a, we tranpose the dimensions i and j of it.
E.g., let a be a tensor of size x * y * z, i = 0, j = 2, 
then the output will be a tensor of size z * y * x.

>> a - the input tensor
>> i - the transposed dimension
>> j - the transposed dimension
<< return - the output tensor by transpose tensor a with specified dimensions i and j
*/
XTensor Transpose(const XTensor &a, const int i, const int j)
{
    CheckNTErrors(a.order > i && i >= 0, "index of dimension is out of scope!");
    CheckNTErrors(a.order > j && j >= 0, "index of dimension is out of scope!");

    int order = a.order;
    int * dimSize = new int[order];
    for(int k = 0; k < order; k++){
        if(k == i)
            dimSize[k] = a.dimSize[j];
        else if(k == j)
            dimSize[k] = a.dimSize[i];
        else
            dimSize[k] = a.dimSize[k];
    }

    float dr = (!a.isSparse) ? 1.0F : a.denseRatio;
    XTensor b(order, dimSize, a.dataType, dr, a.devID, a.mem);
xiaotong committed
141
    b.SetTMPFlag();
142 143 144 145 146

    /* call _Transpose function */
    _Transpose(&a, &b, i, j);
    
    /* tensor connection */
147 148 149 150 151
    if (a.enableGrad) {
        XLink::MakeLink(&a, NULL, &b, SHAPE_TRANSPOSE);
        XLink::AddParamToHeadInt(&b, i);
        XLink::AddParamToHeadInt(&b, j);
    }
152 153 154 155 156 157 158 159

    /* destroy variables */
    delete[] dimSize;

    return b;
}

}