public Matrix(List <List <Operand> > listOfOperandLists) { this.rows = listOfOperandLists.Count; this.cols = 0; for (int i = 0; i < rows; i++) { if (listOfOperandLists[i].Count > cols) { cols = listOfOperandLists[i].Count; } } operandArray = new Operand[rows, cols]; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { try { operandArray[i, j] = listOfOperandLists[i][j]; } catch (Exception) // TODO: Catch specific out-of-bounds exception here. { operandArray[i, j] = new NumericScalar(0.0); } } } }
public void ResetAsIdentity() { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { operandArray[i, j] = new NumericScalar(i == j ? 1.0 : 0.0); } } }
public Matrix(Matrix <double> matrix) : base() { this.rows = matrix.RowCount; this.cols = matrix.ColumnCount; operandArray = new Operand[rows, cols]; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { operandArray[i, j] = new NumericScalar(matrix.At(i, j)); } } }
// Notice that we try to cull by grade first before evaluating our main argument. // This is what may be an optimization by early detection of grade. We must evaluate // our main argument as long as its grade remains indeterminant. How good the optimization // is depends on how well we can determine the grade of an arbitrary operand tree. // Of course, some trees well never have a grade, such as a sum of blades of non-homogeneous grade. public override Operand EvaluationStep(Context context) { if (operandList.Count < 2) { throw new MathException(string.Format("Grade-part operation expects two or more arguments, got {0}.", operandList.Count)); } int grade = operandList[0].Grade; if (grade == -1) { Operand operand = base.EvaluationStep(context); if (operand != null) { return(operand); } } else { var gradeSet = new HashSet <int>(); for (int i = 1; i < operandList.Count; i++) { NumericScalar scalar = operandList[i] as NumericScalar; if (scalar == null) { Operand operand = operandList[i].EvaluationStep(context); if (operand != null) { operandList[i] = operand; return(this); } throw new MathException("Encountered non-numeric-scalar when looking for grade arguments."); } gradeSet.Add((int)scalar.value); } if (gradeSet.Contains(grade)) { return(operandList[0]); } return(new NumericScalar(0.0)); } return(null); }
public override Operand EvaluationStep(Context context) { if (operandList.Count == 0) { return(new NumericScalar(1.0)); } Operand operand; for (int i = 0; i < operandList.Count; i++) { operand = operandList[i]; if (operand.IsAdditiveIdentity) { return(new NumericScalar(0.0)); } if (operand.IsMultiplicativeIdentity) { operandList.RemoveAt(i); return(this); } } operand = base.EvaluationStep(context); if (operand != null) { return(operand); } for (int i = 0; i < operandList.Count; i++) { Operand operandA = operandList[i]; for (int j = i + 1; j < operandList.Count; j++) { Operand operandB = operandList[j]; Operand product = null; if (operandA is NumericScalar scalarA && operandB is NumericScalar scalarB) { product = new NumericScalar(scalarA.value * scalarB.value); }
public List <RowOperation> GaussJordanEliminate(Context context) { List <RowOperation> rowOperationList = new List <RowOperation>(); int pivotRow = 0; int pivotCol = 0; while (pivotRow < this.rows && pivotCol < this.cols) { // // Step 1: If we have a zero in our pivot location, we need to find a non-zero entry in our pivot column. // if (operandArray[pivotRow, pivotCol].IsAdditiveIdentity) { int i; for (i = pivotRow + 1; i < this.rows; i++) { if (!operandArray[i, pivotCol].IsAdditiveIdentity) { break; } } if (i == this.rows) { // Go to the next column. pivotCol++; continue; } else { // Get a non-zero entry into our pivot location. var rowOp = new SwapRows(i, pivotRow); rowOperationList.Add(rowOp); rowOp.Apply(this, context); } } // // Step 2: If we don't have a one in our pivot location, we need to scale our pivot row. // if (!operandArray[pivotRow, pivotCol].IsMultiplicativeIdentity) { var rowOp = new ScaleRow(pivotRow, new Inverse(new List <Operand>() { operandArray[pivotRow, pivotCol].Copy() })); rowOperationList.Add(rowOp); rowOp.Apply(this, context); // TODO: This is a hack until the algebra system can recognize the ratio of two identical polynomials as being one. if (!operandArray[pivotRow, pivotCol].IsMultiplicativeIdentity) { operandArray[pivotRow, pivotCol] = new NumericScalar(1.0); } } // // Step 3: All other entries in our pivot column must be reduced to zero. // for (int i = 0; i < this.rows; i++) { if (i != pivotRow && !operandArray[i, pivotCol].IsAdditiveIdentity) { var rowOp = new AddRowMultiple(i, pivotRow, new GeometricProduct(new List <Operand>() { new NumericScalar(-1.0), operandArray[i, pivotCol].Copy() })); rowOperationList.Add(rowOp); rowOp.Apply(this, context); // TODO: Again, this is a hack, because the algebra system does not yet handle ratios of polynomials very well at all. if (!operandArray[i, pivotCol].IsAdditiveIdentity) { operandArray[i, pivotCol] = new NumericScalar(0.0); } } } // // Step 4: The pivot row always increments, but the next pivot column needs to be determined. // if (++pivotRow < this.rows) { while (++pivotCol < this.cols) { if (!Enumerable.Range(pivotRow, this.rows - pivotRow).Select(i => operandArray[i, pivotCol]).All(operand => operand.IsAdditiveIdentity)) { break; } } } } return(rowOperationList); }