/// <summary> /// Determina a soma de duas matrizes multidimensionais. /// </summary> /// <param name="right">A matriz multidimensional a ser somada.</param> /// <param name="semiGroup">O semi-grupo responsável pelas operações sobre os coeficientes.</param> /// <returns>O resultado da soma.</returns> /// <exception cref="ArgumentNullException">Se um dos argumentos for nulo.</exception> public MultiDimensionalMathRange <T> Sum(MultiDimensionalMathRange <T> right, ISemigroup <T> semiGroup) { if (right == null) { throw new ArgumentNullException("right"); } if (semiGroup == null) { throw new ArgumentNullException("Semi group structure is needed."); } if (!this.CheckDimension(right.configuration)) { throw new MathematicsException("Can only sum ranges with the same dimensions."); } var result = new MultiDimensionalMathRange <T>(); Array.Copy(this.configuration, result.configuration, this.configuration.Length); var p = 1; for (int i = 0; i < this.configuration.Length; ++i) { p *= this.configuration[i]; } result.elements = new T[p]; for (int i = 0; i < this.elements.Length; ++i) { result.elements[i] = semiGroup.Add(this.elements[i], right.elements[i]); } return(result); }
/// <summary> /// Determina o produto de duas matrizes multidimensionais. /// </summary> /// <param name="right">A matriz multidimensional a ser somada.</param> /// <param name="multiplyable">O objeto responsável pelas operações sobre os coeficientes.</param> /// <returns>O resultado do produto.</returns> /// <exception cref="ArgumentNullException">Se um dos argumentos for nulo.</exception> public MultiDimensionalMathRange <T> Multiply(MultiDimensionalMathRange <T> right, IMultiplication <T> multiplyable) { if (right == null) { throw new ArgumentNullException("right"); } if (multiplyable == null) { throw new ArgumentNullException("A multiplyable structure is needed."); } var result = new MultiDimensionalMathRange <T>(); if (this.configuration.Length == 0 || right.configuration.Length == 0) { result.configuration = new int[0]; result.elements = new T[0]; } else { var p = 1; var q = 1; for (int i = 0; i < this.configuration.Length; ++i) { p *= this.configuration[i]; } for (int i = 0; i < right.configuration[i]; ++i) { q *= right.configuration[i]; } result.elements = new T[p * q]; result.configuration = new int[this.configuration.Length + right.configuration.Length]; for (int i = 0; i < this.configuration.Length; ++i) { result.configuration[i] = this.configuration[i]; } for (int i = 0; i < right.configuration.Length; ++i) { result.configuration[this.configuration.Length + i] = right.configuration[i]; } for (int i = 0; i < p; ++i) { for (int j = 0; j < q; ++j) { result.elements[j * p + i] = multiplyable.Multiply(this.elements[i], right.elements[j]); } } } return(result); }
/// <summary> /// Determina a contracção da matriz corrente segundo os índices espcificados. /// </summary> /// <param name="contractionIndices">A matriz multidimensional a ser somada.</param> /// <param name="semiGroup">O objeto responsável pelas operações sobre os coeficientes.</param> /// <returns>O resultado do produto.</returns> /// <exception cref="ArgumentNullException">Se um dos argumentos for nulo.</exception> public MultiDimensionalMathRange <T> Contract(int[] contractionIndices, ISemigroup <T> semiGroup) { if (contractionIndices == null) { throw new ArgumentNullException("contractionIndices"); } if (semiGroup == null) { throw new MathematicsException("Parameter semiGroup can't be null."); } var result = new MultiDimensionalMathRange <T>(); this.CheckConversion(contractionIndices); if (contractionIndices.Length == this.configuration.Length) { result.elements = new T[1]; var advance = 0; for (int i = this.configuration.Length - 1; i > 0; --i) { advance *= this.configuration[i]; advance += 1; } var pos = advance; for (int i = 1; i < this.configuration.Length; ++i) { result.elements[0] = semiGroup.Add(result.elements[0], this.elements[pos]); pos += advance; } result.configuration = new[] { 0 }; } else { var contractionMask = new int[this.configuration.Length]; var newConfigurationCount = 0; for (int i = 0; i < this.configuration.Length; ++i) { if (!contractionIndices.Contains(i)) { contractionMask[i] = 1; } else { ++newConfigurationCount; } } var newSize = 1; result.configuration = new int[newConfigurationCount]; var pointer = 0; for (int i = 0; i < this.configuration.Length; ++i) { if (contractionMask[i] == 1) { newSize *= this.configuration[i]; result.configuration[pointer++] = this.configuration[i]; } } var oldAdvances = new int[this.configuration.Length - newConfigurationCount]; var oldConfig = new int[oldAdvances.Length]; pointer = oldAdvances.Length; var advance = 1; for (int i = 0; i < this.configuration.Length; ++i) { if (contractionMask[i] == 0) { oldConfig[pointer] = this.configuration[i]; oldAdvances[pointer++] = advance; } advance *= this.configuration[i]; } advance = 0; for (int i = this.configuration.Length - 1; i > 0; --i) { advance *= this.configuration[i]; advance += contractionMask[i]; } result.elements = new T[newSize]; var oldCoords = new int[oldConfig.Length]; pointer = 0; for (int i = 0; i < newSize; ++i) { result.elements[i] = this.elements[pointer]; while (pointer < this.elements.Length) { result.elements[i] = semiGroup.Add(result.elements[i], result.elements[pointer]); pointer += advance; } pointer = this.Increment(oldCoords, oldConfig, oldAdvances); } } return(result); }