github.com/wzzhu/tensor@v0.9.24/dense_matop_memmove.go (about)

     1  package tensor
     2  
     3  import "github.com/pkg/errors"
     4  
     5  // This file contains code pertaining to tensor operations that actually move memory
     6  
     7  // Transpose() actually transposes the data.
     8  // This is a generalized version of the inplace matrix transposition algorithm from Wikipedia:
     9  // https://en.wikipedia.org/wiki/In-place_matrix_transposition
    10  func (t *Dense) Transpose() error {
    11  	// if there is no oldinfo, that means the current info is the latest, and not the transpose
    12  	if t.old.IsZero() {
    13  		return nil
    14  	}
    15  
    16  	if t.IsScalar() {
    17  		return nil // cannot transpose scalars - no data movement
    18  	}
    19  
    20  	defer func() {
    21  		t.old.zero()
    22  		t.transposeWith = nil
    23  	}()
    24  
    25  	expShape := t.Shape()
    26  
    27  	// important! because the strides would have changed once the underlying data changed
    28  	var expStrides []int
    29  	if t.AP.o.IsColMajor() {
    30  		expStrides = expShape.CalcStridesColMajor()
    31  	} else {
    32  		expStrides = expShape.CalcStrides()
    33  	}
    34  	defer ReturnInts(expStrides)
    35  	defer func() {
    36  		copy(t.AP.strides, expStrides) // dimensions do not change, so it's actually safe to do this
    37  		t.sanity()
    38  	}()
    39  
    40  	if t.IsVector() {
    41  		// no data movement
    42  		return nil
    43  	}
    44  
    45  	// actually move data
    46  	var e Engine = t.e
    47  
    48  	transposer, ok := e.(Transposer)
    49  	if !ok {
    50  		return errors.Errorf("Engine does not support Transpose()")
    51  	}
    52  	return transposer.Transpose(t, expStrides)
    53  }
    54  
    55  // Repeat is like Numpy's repeat. It repeats the elements of an array.
    56  // The repeats param defines how many times each element in the axis is repeated.
    57  // Just like NumPy, the repeats param is broadcasted to fit the size of the given axis.
    58  func (t *Dense) Repeat(axis int, repeats ...int) (retVal Tensor, err error) {
    59  	e := t.Engine()
    60  
    61  	if rp, ok := e.(Repeater); ok {
    62  		return rp.Repeat(t, axis, repeats...)
    63  	}
    64  	return nil, errors.New("Engine does not support Repeat")
    65  }
    66  
    67  // Concat concatenates the other tensors along the given axis. It is like Numpy's concatenate() function.
    68  func (t *Dense) Concat(axis int, Ts ...*Dense) (retVal *Dense, err error) {
    69  	e := t.Engine()
    70  
    71  	if c, ok := e.(Concater); ok {
    72  		var ret Tensor
    73  		others := densesToTensors(Ts)
    74  		if ret, err = c.Concat(t, axis, others...); err != nil {
    75  			return nil, errors.Wrapf(err, opFail, "Concat")
    76  		}
    77  		return ret.(*Dense), nil
    78  	}
    79  	return nil, errors.New("Engine does not support Concat")
    80  }
    81  
    82  // Hstack stacks other tensors columnwise (horizontal stacking)
    83  func (t *Dense) Hstack(others ...*Dense) (*Dense, error) {
    84  	// check that everything is at least 1D
    85  	if t.Dims() == 0 {
    86  		return nil, errors.Errorf(atleastDims, 1)
    87  	}
    88  
    89  	for _, d := range others {
    90  		if d.Dims() < 1 {
    91  			return nil, errors.Errorf(atleastDims, 1)
    92  		}
    93  	}
    94  
    95  	if t.Dims() == 1 {
    96  		return t.Concat(0, others...)
    97  	}
    98  	return t.Concat(1, others...)
    99  }
   100  
   101  // Vstack stacks other tensors rowwise (vertical stacking). Vertical stacking requires all involved Tensors to have at least 2 dimensions
   102  func (t *Dense) Vstack(others ...*Dense) (*Dense, error) {
   103  	// check that everything is at least 2D
   104  	if t.Dims() < 2 {
   105  		return nil, errors.Errorf(atleastDims, 2)
   106  	}
   107  
   108  	for _, d := range others {
   109  		if d.Dims() < 2 {
   110  			return nil, errors.Errorf(atleastDims, 2)
   111  		}
   112  	}
   113  	return t.Concat(0, others...)
   114  }
   115  
   116  // Stack stacks the other tensors along the axis specified. It is like Numpy's stack function.
   117  func (t *Dense) Stack(axis int, others ...*Dense) (retVal *Dense, err error) {
   118  	var ret DenseTensor
   119  	var ok bool
   120  	if ret, err = t.stackDense(axis, densesToDenseTensors(others)...); err != nil {
   121  		return nil, err
   122  	}
   123  	if retVal, ok = ret.(*Dense); !ok {
   124  		return nil, errors.Errorf("Return not *Dense")
   125  	}
   126  	return
   127  }
   128  
   129  func (t *Dense) stackDense(axis int, others ...DenseTensor) (retVal DenseTensor, err error) {
   130  	if ds, ok := t.Engine().(DenseStacker); ok {
   131  		return ds.StackDense(t, axis, others...)
   132  	}
   133  	return nil, errors.Errorf("Engine does not support DenseStacker")
   134  }