public ImmutableDenseMatrix <TDataType, TOperationDefiner> Subtract(
            ImmutableDenseMatrix <TDataType, TOperationDefiner> addend)
        {
            if (!SameSize(addend))
            {
                throw new ArgumentOutOfRangeException(nameof(addend),
                                                      (addend), "Addend must be same size as the matrix");
            }

            var items     = addend.Items;
            var itemCount = ItemCount;
            var array     = new TDataType[itemCount];

            for (int i = 0; i < itemCount; i++)
            {
                array[i] = _opDef.Add(Items[i], _opDef.Negative(items[i]));
            }
            return(new ImmutableDenseMatrix <TDataType, TOperationDefiner>(array.UnsafeMakeImmutable(), RowCount, ColumnCount));
        }
        public bool Equals(ImmutableDenseMatrix <TDataType, TOperationDefiner> equand)
        {
            if (equand == null)
            {
                return(false);
            }
            if (!SameSize(equand))
            {
                return(false);
            }
            var items = equand.Items;

            for (int i = 0; i < ItemCount; i++)
            {
                if (!_opDef.Equals(Items[i], items[i]))
                {
                    return(false);
                }
            }
            return(true);
        }
        public ImmutableDenseMatrix <TDataType, TOperationDefiner> Multiply(ImmutableDenseMatrix <TDataType, TOperationDefiner> multiplicand)
        {
            if (!CanMultiply(multiplicand))
            {
                throw new ArgumentOutOfRangeException(nameof(multiplicand),
                                                      (multiplicand), "Multiplicand must have the same number of rows as the matrix has columns");
            }

            var thatItems = multiplicand.Items;

            var array = new TDataType[RowCount * multiplicand.ColumnCount];
            var zero  = _opDef.Zero;

            var columnCount     = ColumnCount;
            var rowCount        = RowCount;
            var thatColumnCount = multiplicand.ColumnCount;

            var resultPointer = 0;

            for (int i = 0; i < rowCount; i++)
            {
                for (int j = 0; j < thatColumnCount; j++, resultPointer++)
                {
                    var thisPointer = columnCount * i;
                    var thatPointer = j;
                    var sum         = zero;
                    for (int k = 0; k < columnCount; k++, thisPointer++, thatPointer += thatColumnCount)
                    {
                        sum = _opDef.Add(sum, _opDef.Multiply(Items[thisPointer], thatItems[thatPointer]));
                    }
                    array[resultPointer] = sum;
                }
            }

            return(new ImmutableDenseMatrix <TDataType, TOperationDefiner>(array.UnsafeMakeImmutable(), rowCount, thatColumnCount));
        }