Exemple #1
0
        private void WriteToStream(ISparseMatrix matrix, StreamWriter writer)
        {
            SparseFormat sparseFormat = matrix.GetSparseFormat();

            writer.Write(sparseFormat.RawValuesTitle + ": ");
            if (titlesOnOtherLines)
            {
                writer.WriteLine();
            }
            WriteArray(sparseFormat.RawValuesArray, writer, false);

            foreach (var nameArrayPair in sparseFormat.RawIndexArrays)
            {
                if (lineBetweenArrays)
                {
                    writer.WriteLine();
                }
                writer.WriteLine(); // otherwise everything would be on the same line
                writer.Write(nameArrayPair.Key + ": ");
                if (titlesOnOtherLines)
                {
                    writer.WriteLine();
                }
                WriteArray(nameArrayPair.Value, writer, false);
            }
        }
Exemple #2
0
        /// <summary>
        /// Links matrix elements.
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="row">The row variable.</param>
        /// <param name="column">The column variable.</param>
        private void LinkElement(ISparseMatrix <T> matrix, Bridge <int> row, Bridge <int> column)
        {
            var loc = Solver.ExternalToInternal(new MatrixLocation(row.Local, column.Local));

            // Do we need to create an element?
            var local_elt = matrix.FindElement(loc);

            if (local_elt == null)
            {
                // Check if solving will result in an element
                var left = matrix.GetFirstInRow(loc.Row);
                if (left == null || left.Column > Solver.Size - Solver.Degeneracy)
                {
                    return;
                }

                var top = matrix.GetFirstInColumn(loc.Column);
                if (top == null || top.Row > Solver.Size - Solver.Degeneracy)
                {
                    return;
                }

                // Create the element because decomposition will cause these elements to be created
                local_elt = matrix.GetElement(loc);
            }
            if (local_elt == null)
            {
                return;
            }
            var parent_elt = Parent.Solver.GetElement(new MatrixLocation(row.Global, column.Global));

            _elements.Add(new Bridge <Element <T> >(local_elt, parent_elt));
        }
Exemple #3
0
        /// <summary>
        /// Notifies the strategy that a fill-in has been created
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="fillin">The fill-in.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> or <paramref name="fillin"/> is <c>null</c>.
        /// </exception>
        public void CreateFillin(ISparseMatrix <T> matrix, ISparseMatrixElement <T> fillin)
        {
            matrix.ThrowIfNull(nameof(matrix));
            fillin.ThrowIfNull(nameof(fillin));

            if (_markowitzProduct == null)
            {
                return;
            }

            // Update the markowitz row count
            int index = fillin.Row;

            _markowitzRow[index]++;
            _markowitzProduct[index] =
                Math.Min(_markowitzRow[index] * _markowitzColumn[index], _maxMarkowitzCount);
            if (_markowitzRow[index] == 1 && _markowitzColumn[index] != 0)
            {
                Singletons--;
            }

            // Update the markowitz column count
            index = fillin.Column;
            _markowitzColumn[index]++;
            _markowitzProduct[index] =
                Math.Min(_markowitzRow[index] * _markowitzColumn[index], _maxMarkowitzCount);
            if (_markowitzRow[index] != 0 && _markowitzColumn[index] == 1)
            {
                Singletons--;
            }
        }
Exemple #4
0
        /// <summary>
        /// Accumulates an identity matrix, but only for selected variabels
        /// </summary>
        /// <param name="M">matrix to be modified (input/output)</param>
        /// <param name="factor"></param>
        /// <param name="iVar"></param>
        static public void AccEyeSp(this ISparseMatrix M, UnsetteledCoordinateMapping map, int[] iVar, double factor = 1.0)
        {
            using (new FuncTrace()) {
                if (M.RowPartitioning.LocalLength != M.ColPartition.LocalLength)
                {
                    throw new ArgumentException("supported only for quadratic matrices");
                }
                if (map.LocalLength != M.RowPartitioning.LocalLength)
                {
                    throw new ArgumentException();
                }

                int J = map.GridDat.iLogicalCells.NoOfLocalUpdatedCells;

                for (int j = 0; j < J; j++)
                {
                    foreach (int f in iVar)
                    {
                        int Np = map.BasisS[f].GetLength(j);

                        for (int n = 0; n < Np; n++)
                        {
                            int idx = map.GlobalUniqueCoordinateIndex(f, j, n);

                            M.SetDiagonalElement(idx, M.GetDiagonalElement(idx) + factor);
                        }
                    }
                }
            }
        }
Exemple #5
0
        /// <summary>
        /// Writes each internal array of the provided sparse matrix to a different file. All these filenames have a common
        /// prefix, extracted from <paramref name="pathBase"/>, and a suffix corresponding to the purpose of each array.
        /// </summary>
        /// <param name="matrix">The sparse matrix to write.</param>
        /// <param name="pathBase">An absolute path. This filename will not be used directly. Instead one file per internal array
        ///     of <paramref name="matrix"/> will be used. Each file will be suffixed with the name of that array and then the
        ///     extension specified in <paramref name="pathBase"/>.</param>
        /// <param name="writeArrayLengthFirst">If true, the first line of each file will contain the length of the corresponding
        ///     array. If false, there will be only one line per file, which will contain the array.</param>
        public void WriteToMultipleFiles(ISparseMatrix matrix, string pathBase, bool writeArrayLengthFirst = true) // TODO: this should be a different writer
        {
            string       path         = Path.GetDirectoryName(pathBase);
            string       nameOnly     = Path.GetFileNameWithoutExtension(pathBase);
            string       ext          = Path.GetExtension(pathBase);
            SparseFormat sparseFormat = matrix.GetSparseFormat();

            // Values array
            string suffix     = "-" + sparseFormat.RawValuesTitle.ToLower();
            string valuesPath = path + "\\" + nameOnly + suffix + ext; // Not too sure about the \\

            using (var writer = new StreamWriter(valuesPath))
            {
#if DEBUG
                writer.AutoFlush = true; // To look at intermediate output at certain breakpoints
#endif
                WriteArray(sparseFormat.RawValuesArray, writer, writeArrayLengthFirst);
            }

            // Indexing arrays
            foreach (var nameArrayPair in sparseFormat.RawIndexArrays)
            {
                suffix = "-" + nameArrayPair.Key.ToLower();
                string indexerPath = path + "\\" + nameOnly + suffix + ext; // Not too sure about the \\
                using (var writer = new StreamWriter(indexerPath))
                {
#if DEBUG
                    writer.AutoFlush = true; // To look at intermediate output at certain breakpoints
#endif
                    WriteArray(nameArrayPair.Value, writer, writeArrayLengthFirst);
                }
            }
        }
        private static void TestWriteOperation(ISparseMatrix matrix, string referenceFile, RawArraysWriter writer)
        {
            string tempFile = Guid.NewGuid().ToString() + ".txt";

            writer.WriteToFile(matrix, tempFile);
            bool success = IOUtilities.AreFilesEquivalent(referenceFile, tempFile);

            File.Delete(tempFile);
            Assert.True(success);
        }
Exemple #7
0
 public static void GetI0(ref int _ref, out int i0, out int ierr)
 {
     ierr = 0;
     i0   = -1;
     try {
         ISparseMatrix M = (ISparseMatrix)Infrastructure.GetObject(_ref);
         i0 = (int)M.RowPartitioning.i0;
     } catch (Exception e) {
         ierr = Infrastructure.ErrorHandler(e);
     }
 }
Exemple #8
0
 public static void GetLocLen(ref int _ref, out int LocLen, out int ierr)
 {
     ierr   = 0;
     LocLen = -1;
     try {
         ISparseMatrix M = (ISparseMatrix)Infrastructure.GetObject(_ref);
         LocLen = M.RowPartitioning.LocalLength;
     } catch (Exception e) {
         ierr = Infrastructure.ErrorHandler(e);
     }
 }
Exemple #9
0
        private void Count(ISparseMatrix <T> matrix, ISparseVector <T> rhs, int step, int max)
        {
            ISparseMatrixElement <T> element;

            // Get the first element in the vector
            var rhsElement = rhs.GetFirstInVector();

            // Generate Markowitz row count
            for (var i = max; i >= step; i--)
            {
                // Set count to -1 initially to remove count due to pivot element
                var count = -1;
                element = matrix.GetFirstInRow(i);
                while (element != null && element.Column < step)
                {
                    element = element.Right;
                }
                while (element != null) // We want to count the elements outside the limit as well
                {
                    count++;
                    element = element.Right;
                }

                // Include elements on the Rhs vector
                while (rhsElement != null && rhsElement.Index < step)
                {
                    rhsElement = rhsElement.Below;
                }
                if (rhsElement != null && rhsElement.Index == i)
                {
                    count++;
                }

                _markowitzRow[i] = Math.Min(count, _maxMarkowitzCount);
            }

            // Generate Markowitz column count
            for (var i = step; i <= max; i++)
            {
                // Set count to -1 initially to remove count due to pivot element
                var count = -1;
                element = matrix.GetFirstInColumn(i);
                while (element != null && element.Row < step)
                {
                    element = element.Below;
                }
                while (element != null)
                {
                    count++;
                    element = element.Below;
                }
                _markowitzColumn[i] = Math.Min(count, _maxMarkowitzCount);
            }
        }
Exemple #10
0
 public static void GetRowPart(ref int MtxRef, out int PartRef, out int ierr)
 {
     ierr    = 0;
     PartRef = -1;
     try {
         ISparseMatrix M = (ISparseMatrix)Infrastructure.GetObject(MtxRef);
         PartRef = Infrastructure.RegisterObject(M.RowPartitioning);
     } catch (Exception e) {
         ierr = Infrastructure.ErrorHandler(e);
     }
 }
        private void WriteSparseMatrix(ISparseMatrix matrix, StreamWriter writer)
        {
            string numberFormat = NumericFormat.GetRealNumberFormat();

            foreach (var(row, col, val) in matrix.EnumerateNonZeros())
            {
                writer.Write($"{row + 1} {col + 1} ");
                writer.WriteLine(string.Format(numberFormat, val));
            }
            writer.Write($"{matrix.NumRows} {matrix.NumColumns} 0.0");
        }
Exemple #12
0
        /// <summary>
        /// Setup the pivot strategy.
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="rhs">The right-hand side vector.</param>
        /// <param name="eliminationStep">The current elimination step.</param>
        /// <param name="max">The maximum row/column index.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> or <paramref name="rhs"/> is <c>null</c>.
        /// </exception>
        public void Setup(ISparseMatrix <T> matrix, ISparseVector <T> rhs, int eliminationStep, int max)
        {
            matrix.ThrowIfNull(nameof(matrix));
            rhs.ThrowIfNull(nameof(rhs));

            // Initialize Markowitz row, column and product vectors if necessary
            if (_markowitzRow == null || _markowitzRow.Length != matrix.Size + 1)
            {
                Initialize(matrix);
            }
            Count(matrix, rhs, eliminationStep, max);
            Products(eliminationStep, max);
        }
Exemple #13
0
        /// <summary>
        /// Update the strategy after the pivot was moved.
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="pivot">The pivot element.</param>
        /// <param name="limit">The maximum row/column for pivots.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> or <paramref name="pivot"/> is <c>null</c>.
        /// </exception>
        public void Update(ISparseMatrix <T> matrix, ISparseMatrixElement <T> pivot, int limit)
        {
            matrix.ThrowIfNull(nameof(matrix));
            pivot.ThrowIfNull(nameof(pivot));

            // If we haven't setup, just skip
            if (_markowitzProduct == null)
            {
                return;
            }

            // Go through all elements below the pivot. If they exist, then we can subtract 1 from the Markowitz row vector!
            for (var column = pivot.Below; column != null && column.Row <= limit; column = column.Below)
            {
                var row = column.Row;

                // Update the Markowitz product
                _markowitzProduct[row] -= _markowitzColumn[row];
                --_markowitzRow[row];

                // If we reached 0, then the row just turned to a singleton row
                if (_markowitzRow[row] == 0)
                {
                    Singletons++;
                }
            }

            // go through all elements right of the pivot. For every element, we can subtract 1 from the Markowitz column vector!
            for (var row = pivot.Right; row != null && row.Column <= limit; row = row.Right)
            {
                var column = row.Column;

                // Update the Markowitz product
                _markowitzProduct[column] -= _markowitzRow[column];
                --_markowitzColumn[column];

                // If we reached 0, then the column just turned to a singleton column
                // This only adds a singleton if the row wasn't detected as a singleton row first
                if (_markowitzColumn[column] == 0 && _markowitzRow[column] != 0)
                {
                    Singletons++;
                }
            }
        }
Exemple #14
0
        /// <summary>
        /// Adds <paramref name="factor"/> to all diagonal entries of <paramref name="M"/>.
        /// </summary>
        static public void AccEyeSp(this ISparseMatrix M, double factor = 1.0)
        {
            using (new FuncTrace()) {
                if (M.RowPartitioning.LocalLength != M.ColPartition.LocalLength)
                {
                    throw new ArgumentException("supported only for quadratic matrices");
                }

                var rm = M.RowPartitioning;

                int i0 = (int)rm.i0;
                int L  = rm.LocalLength;

                for (int i = 0; i < L; i++)
                {
                    M.SetDiagonalElement(i + i0, M.GetDiagonalElement(i + i0) + factor);
                }
            }
        }
Exemple #15
0
        /// <summary>
        /// Find a pivot in the matrix.
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="eliminationStep">The current elimination step.</param>
        /// <param name="max">The maximum row/column index of any pivot.</param>
        /// <returns>The pivot information.</returns>
        /// <remarks>
        /// The pivot should be searched for in the submatrix towards the right and down of the
        /// current diagonal at row/column <paramref name="eliminationStep" />. This pivot element
        /// will be moved to the diagonal for this elimination step.
        /// </remarks>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="matrix"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Thrown if <paramref name="eliminationStep"/> or <paramref name="max"/> not 1 or higher,
        /// or <paramref name="eliminationStep"/> is higher than <paramref name="max"/>.
        /// </exception>
        public Pivot <ISparseMatrixElement <T> > FindPivot(ISparseMatrix <T> matrix, int eliminationStep, int max)
        {
            matrix.ThrowIfNull(nameof(matrix));
            eliminationStep.GreaterThan(nameof(eliminationStep), 0);
            max.GreaterThan(nameof(max), 0);

            // No pivot possible if we're already eliminating outside of our bounds
            if (eliminationStep > max)
            {
                return(Pivot <ISparseMatrixElement <T> > .Empty);
            }

            // Fix the search limit to allow our strategies to work
            foreach (var strategy in Strategies)
            {
                var chosen = strategy.FindPivot(this, matrix, eliminationStep, max);
                if (chosen.Info != PivotInfo.None)
                {
                    return(chosen);
                }
            }
            return(Pivot <ISparseMatrixElement <T> > .Empty);
        }
Exemple #16
0
        /// <summary>
        /// Solves the linear system (diag(1/<paramref name="dt"/>) +
        /// <em>M</em> / 2) * x =
        /// <see cref="ImplicitTimeStepper.CurrentState"/> /
        /// <paramref name="dt"/> -
        /// <em>M</em> *
        /// <see cref="ImplicitTimeStepper.CurrentState"/> / 2 -
        /// 0.5*(<see cref="ImplicitTimeStepper.m_AffineOffset1"/> +
        /// <see cref="m_AffineOffset0"/> )
        /// and writes the
        /// result do <see cref="ImplicitTimeStepper.CurrentState"/>.
        /// </summary>
        /// <param name="dt">The length of the timestep</param>
        protected override void PerformTimeStep(double dt)
        {
            using (var tr = new ilPSP.Tracing.FuncTrace()) {
                if (m_Theta <= 0 || m_Theta > 1)
                {
                    throw new ApplicationException("m_Theta out of range; must be betwwen 0.0 (including) and 1.0 (including), but m_Theta = " + m_Theta);
                }

                int n  = Mapping.LocalLength;
                int np = m_diagVecOneSec.Length;

                double[] diag = new double[n];
                for (int i = 0; i < n; i++)
                {
                    diag[i] = m_diagVecOneSec[i % np];
                }
                BLAS.dscal(n, 1.0 / (m_Theta * dt), diag, 1);

                double[] rhs;
                if (m_AffineOffset0 != null)
                {
                    rhs = m_AffineOffset0;
                    BLAS.dscal(rhs.Length, -(1.0 - m_Theta) / m_Theta, rhs, 1);
                    BLAS.daxpy(rhs.Length, -1.0, m_AffineOffset1, 1, rhs, 1);
                }
                else
                {
                    rhs = (double[])m_AffineOffset1.Clone();
                }

                if (m_Theta != 1.0)
                {
                    // if m_Theta == 0.0, this has no effect and is a waste of comp. power
                    ISparseMatrix eM = m_Solver.GetMatrix();
                    eM.SpMV <CoordinateVector, double[]>(-(1.0 - m_Theta) / m_Theta, CurrentState, 1.0, rhs);
                }

                for (int i = 0; i < n; i++)
                {
                    rhs[i] += diag[i] * CurrentState[i];
                    // fraglich
                }

                tr.Info("Calling solver");
                LastSolverResult = m_Solver.Solve <double[], CoordinateVector, double[]>(1.0, diag, CurrentState, rhs);
                tr.Info("no. of iterations: " + LastSolverResult.NoOfIterations);
                tr.Info("converged? : " + LastSolverResult.Converged);
                tr.Info("Pure solver runtime: " + LastSolverResult.RunTime.TotalSeconds + " sec.");


                /*
                 * int n = Mapping.LocalLength;
                 * int np = m_diagVecOneSec.Length;
                 *
                 * double[] diag = new double[n];
                 * for (int i = 0; i < n; i++) {
                 *  diag[i] = m_diagVecOneSec[i % np];
                 * }
                 * BLAS.dscal(n, 1.0 / dt, diag, 1);
                 *
                 * double[] rhs = (double[])m_AffineOffset1.Clone();
                 * BLAS.dscal(n, -1.0, rhs, 1);
                 *
                 * for (int i = 0; i < n; i++) {
                 *  rhs[i] += diag[i] * DGCoordinates[i];
                 * }
                 *
                 * m_Context.IOMaster.tracer.Message(ht, "Calling solver");
                 * LastSolverResult = m_Solver.Solve<double[], CoordinateVector, double[]>(1.0, diag, DGCoordinates, rhs);
                 */
            }
        }
 private static void TestWriteOperation(ISparseMatrix matrix, string referenceFile)
 => TestWriteOperation(matrix, referenceFile, new CoordinateTextFileWriter());
Exemple #18
0
        /// <inheritdoc/>
        public override Pivot <ISparseMatrixElement <T> > FindPivot(Markowitz <T> markowitz, ISparseMatrix <T> matrix, int eliminationStep, int max)
        {
            markowitz.ThrowIfNull(nameof(markowitz));
            matrix.ThrowIfNull(nameof(matrix));
            if (eliminationStep < 1 || eliminationStep > max)
            {
                return(Pivot <ISparseMatrixElement <T> > .Empty);
            }

            var minMarkowitzProduct         = int.MaxValue;
            ISparseMatrixElement <T> chosen = null;
            var ratioOfAccepted             = 0.0;
            var ties = 0;

            /* Used for debugging alongside Spice 3f5
             * for (var index = matrix.Size + 1; index > eliminationStep; index--)
             * {
             *  var i = index > matrix.Size ? eliminationStep : index; */
            for (var i = eliminationStep; i <= max; i++)
            {
                // Skip the diagonal if we already have a better one
                if (markowitz.Product(i) > minMarkowitzProduct)
                {
                    continue;
                }

                // Get the diagonal
                var diagonal = matrix.FindDiagonalElement(i);
                if (diagonal == null)
                {
                    continue;
                }

                // Get the magnitude
                var magnitude = markowitz.Magnitude(diagonal.Value);
                if (magnitude <= markowitz.AbsolutePivotThreshold)
                {
                    continue;
                }

                // Check that the pivot is eligible
                var largest = 0.0;
                var element = diagonal.Below;
                while (element != null && element.Row <= max)
                {
                    largest = Math.Max(largest, markowitz.Magnitude(element.Value));
                    element = element.Below;
                }
                element = diagonal.Above;
                while (element != null && element.Row >= eliminationStep)
                {
                    largest = Math.Max(largest, markowitz.Magnitude(element.Value));
                    element = element.Above;
                }
                if (magnitude <= markowitz.RelativePivotThreshold * largest)
                {
                    continue;
                }

                // Check markowitz numbers to find the optimal pivot
                if (markowitz.Product(i) < minMarkowitzProduct)
                {
                    // Notice strict inequality, this is a new smallest product
                    chosen = diagonal;
                    minMarkowitzProduct = markowitz.Product(i);
                    ratioOfAccepted     = largest / magnitude;
                    ties = 0;
                }
                else
                {
                    // If we have enough elements with the same (minimum) number of ties, stop searching
                    ties++;
                    var ratio = largest / magnitude;
                    if (ratio < ratioOfAccepted)
                    {
                        chosen          = diagonal;
                        ratioOfAccepted = ratio;
                    }
                    if (ties >= minMarkowitzProduct * _tiesMultiplier)
                    {
                        return(new Pivot <ISparseMatrixElement <T> >(chosen, PivotInfo.Suboptimal));
                    }
                }
            }

            // The chosen pivot has already been checked for validity
            return(chosen != null ? new Pivot <ISparseMatrixElement <T> >(chosen, PivotInfo.Suboptimal) : Pivot <ISparseMatrixElement <T> > .Empty);
        }
        /// <inheritdoc/>
        public override Pivot <ISparseMatrixElement <T> > FindPivot(Markowitz <T> markowitz, ISparseMatrix <T> matrix, int eliminationStep, int max)
        {
            markowitz.ThrowIfNull(nameof(markowitz));
            matrix.ThrowIfNull(nameof(matrix));
            if (eliminationStep < 1 || eliminationStep > max)
            {
                return(Pivot <ISparseMatrixElement <T> > .Empty);
            }

            // No singletons left, so don't bother
            if (markowitz.Singletons == 0)
            {
                return(Pivot <ISparseMatrixElement <T> > .Empty);
            }

            // Find the first valid singleton we can use
            int singletons = 0, index;

            for (var i = max + 1; i >= eliminationStep; i--)
            {
                // First check the current pivot, else
                // search from last to first as this tends to push the higher markowitz
                // products downwards.
                index = i > max ? eliminationStep : i;

                // Not a singleton, let's skip this one...
                if (markowitz.Product(index) != 0)
                {
                    continue;
                }

                // Keep track of how many singletons we have found
                singletons++;

                /*
                 * NOTE: In the sparse library of Spice 3f5 first the diagonal is checked,
                 * then the column is checked (if no success go to row) and finally the
                 * row is checked for a valid singleton pivot.
                 * The diagonal should actually not be checked, as the checking algorithm is the same
                 * as for checking the column (FindBiggestInColExclude will not find anything in the column
                 * for singletons). The original author did not find this.
                 * Also, the original algorithm has a bug in there that renders the whole code invalid...
                 * if (ChosenPivot != NULL) { break; } will throw away the pivot even if it was found!
                 * (ref. Spice 3f5 Libraries/Sparse/spfactor.c, line 1286)
                 */

                // Find the singleton element
                ISparseMatrixElement <T> chosen;
                if (markowitz.ColumnCount(index) == 0)
                {
                    // The last element in the column is the singleton element!
                    chosen = matrix.GetLastInColumn(index);
                    if (chosen.Row <= max && chosen.Column <= max)
                    {
                        // Check if it is a valid pivot
                        var magnitude = markowitz.Magnitude(chosen.Value);
                        if (magnitude > markowitz.AbsolutePivotThreshold)
                        {
                            return(new Pivot <ISparseMatrixElement <T> >(chosen, PivotInfo.Good));
                        }
                    }
                }

                // Check if we can still use a row here
                if (markowitz.RowCount(index) == 0)
                {
                    // The last element in the row is the singleton element
                    chosen = matrix.GetLastInRow(index);

                    // When the matrix has an empty row, and an RHS element, it is possible
                    // that the singleton is not a singleton
                    if (chosen == null || chosen.Column < eliminationStep)
                    {
                        // The last element is not valid, singleton failed!
                        singletons--;
                        continue;
                    }

                    // First find the biggest magnitude in the column, not counting the pivot candidate
                    var element = chosen.Above;
                    var largest = 0.0;
                    while (element != null && element.Row >= eliminationStep)
                    {
                        largest = Math.Max(largest, markowitz.Magnitude(element.Value));
                        element = element.Above;
                    }
                    element = chosen.Below;
                    while (element != null && element.Row <= max)
                    {
                        largest = Math.Max(largest, markowitz.Magnitude(element.Value));
                        element = element.Below;
                    }

                    // Check if the pivot is valid
                    if (chosen.Row <= max && chosen.Column <= max)
                    {
                        var magnitude = markowitz.Magnitude(chosen.Value);
                        if (magnitude > markowitz.AbsolutePivotThreshold &&
                            magnitude > markowitz.RelativePivotThreshold * largest)
                        {
                            return(new Pivot <ISparseMatrixElement <T> >(chosen, PivotInfo.Good));
                        }
                    }
                }

                // Don't continue if no more singletons are available
                if (singletons >= markowitz.Singletons)
                {
                    break;
                }
            }

            // All singletons were unacceptable...
            return(Pivot <ISparseMatrixElement <T> > .Empty);
        }
Exemple #20
0
 /// <summary>
 /// Find a pivot in a matrix.
 /// </summary>
 /// <param name="markowitz">The Markowitz pivot strategy.</param>
 /// <param name="matrix">The matrix.</param>
 /// <param name="eliminationStep">The current elimination step.</param>
 /// <param name="max">The maximum row/column index.</param>
 /// <returns>
 /// The pivot element, or null if no pivot was found.
 /// </returns>
 /// <exception cref="ArgumentNullException">Thrown if <paramref name="markowitz" /> or <paramref name="matrix" /> is <c>null</c>.</exception>
 /// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="eliminationStep" /> or <paramref name="max" /> not 1 or higher,
 /// or <paramref name="eliminationStep" /> is higher than <paramref name="max" />.</exception>
 public abstract Pivot <ISparseMatrixElement <T> > FindPivot(Markowitz <T> markowitz, ISparseMatrix <T> matrix, int eliminationStep, int max);
Exemple #21
0
 /// <summary>
 /// Initializes a new instance of <see cref="DokColMajor"/> with the specified matrix dimensions and the non-zero
 /// entries of the provided sparse matrix.
 /// </summary>
 /// <param name="matrix">A sparse matrix whose dimensions and non-zero entries will be used to intialize the new
 ///     <see cref="DokColMajor"/>.</param>
 public static DokColMajor CreateFromSparseMatrix(ISparseMatrix matrix)
 => CreateFromSparsePattern(matrix.NumRows, matrix.NumColumns, matrix.EnumerateNonZeros());
 private static void TestWriteOperation(ISparseMatrix matrix, string referenceFile)
 => TestWriteOperation(matrix, referenceFile, new RawArraysWriter(true, true));
Exemple #23
0
        /// <summary>
        /// Move the pivot to the diagonal for this elimination step.
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="rhs">The right-hand side vector.</param>
        /// <param name="pivot">The pivot element.</param>
        /// <param name="eliminationStep">The elimination step.</param>
        /// <remarks>
        /// This is done by swapping the rows and columns of the diagonal and that of the pivot.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/>, <paramref name="rhs"/> or <paramref name="pivot"/> is <c>null</c>.
        /// </exception>
        public void MovePivot(ISparseMatrix <T> matrix, ISparseVector <T> rhs, ISparseMatrixElement <T> pivot, int eliminationStep)
        {
            matrix.ThrowIfNull(nameof(matrix));
            rhs.ThrowIfNull(nameof(rhs));
            pivot.ThrowIfNull(nameof(pivot));

            // If we haven't setup, just skip
            if (_markowitzProduct == null)
            {
                return;
            }
            int oldProduct;

            var row = pivot.Row;
            var col = pivot.Column;

            // If the pivot is a singleton, then we just consumed it
            if (_markowitzProduct[row] == 0 || _markowitzProduct[col] == 0)
            {
                Singletons--;
            }

            // Exchange rows
            if (row != eliminationStep)
            {
                // Swap row Markowitz numbers
                var tmp = _markowitzRow[row];
                _markowitzRow[row]             = _markowitzRow[eliminationStep];
                _markowitzRow[eliminationStep] = tmp;

                // Update the Markowitz product
                oldProduct             = _markowitzProduct[row];
                _markowitzProduct[row] = _markowitzRow[row] * _markowitzColumn[row];
                if (oldProduct == 0)
                {
                    if (_markowitzProduct[row] != 0)
                    {
                        Singletons--;
                    }
                }
                else
                {
                    if (_markowitzProduct[row] == 0)
                    {
                        Singletons++;
                    }
                }
            }

            // Exchange columns
            if (col != eliminationStep)
            {
                // Swap column Markowitz numbers
                var tmp = _markowitzColumn[col];
                _markowitzColumn[col]             = _markowitzColumn[eliminationStep];
                _markowitzColumn[eliminationStep] = tmp;

                // Update the Markowitz product
                oldProduct             = _markowitzProduct[col];
                _markowitzProduct[col] = _markowitzRow[col] * _markowitzColumn[col];
                if (oldProduct == 0)
                {
                    if (_markowitzProduct[col] != 0)
                    {
                        Singletons--;
                    }
                }
                else
                {
                    if (_markowitzProduct[col] == 0)
                    {
                        Singletons++;
                    }
                }
            }

            // Also update the moved pivot
            oldProduct = _markowitzProduct[eliminationStep];
            _markowitzProduct[eliminationStep] = _markowitzRow[eliminationStep] * _markowitzColumn[eliminationStep];
            if (oldProduct == 0)
            {
                if (_markowitzProduct[eliminationStep] != 0)
                {
                    Singletons--;
                }
            }
            else
            {
                if (_markowitzProduct[eliminationStep] == 0)
                {
                    Singletons++;
                }
            }
        }
Exemple #24
0
 /// <summary>
 /// Writes the internal arrays of the provided sparse matrix to Console.
 /// </summary>
 /// <param name="matrix">The sparse matrix to write.</param>
 public void WriteToConsole(ISparseMatrix matrix)
 {
     Utilities.WriteToConsole((writer) => WriteToStream(matrix, writer));
 }
Exemple #25
0
 /// <summary>
 /// Writes the internal arrays of the provided sparse matrix to the file at <paramref name="path"/>.
 /// </summary>
 /// <param name="matrix">The sparse matrix to write.</param>
 /// <param name="path">The absolute path of the file, where <paramref name="matrix"/> will be written.</param>
 /// <param name="append">If true, <paramref name="matrix"/> will be written after the current contents of the file at
 ///     <paramref name="path"/>. If false, it will overwrite them.</param>
 public void WriteToFile(ISparseMatrix matrix, string path, bool append = false)
 {
     Utilities.WriteToFile((writer) => WriteToStream(matrix, writer), path, append);
 }
        /// <summary>
        /// Preorders the modified nodal analysis.
        /// </summary>
        /// <param name="matrix">The matrix.</param>
        /// <param name="size">The submatrix size to be preordered.</param>
        public static void PreorderModifiedNodalAnalysis(ISparseMatrix <T> matrix, int size)
        {
            /*
             * MNA often has patterns that we can already use for pivoting
             *
             * For example, the following pattern is quite common (lone twins):
             * ? ... 1
             * .  \  .
             * 1 ... 0
             * We can swap columns to pivot the 1's to the diagonal. This
             * makes searching for pivots faster.
             *
             * We also often have the pattern of double twins:
             * ? ...  ? ...  1
             * .  \   . ...  .
             * ? ...  ? ... -1
             * . ...  .  \   .
             * 1 ... -1 ...  0
             * We can swap either of the columns to pivot the 1 or -1
             * to the diagonal. Note that you can also treat this pattern
             * as 2 twins on the ?-diagonal elements. These should be taken
             * care of first.
             */
            ISparseMatrixElement <T> twin1 = null, twin2 = null;
            var  start = 1;
            bool anotherPassNeeded;

            do
            {
                bool swapped;
                anotherPassNeeded = swapped = false;

                // Search for zero diagonals with lone twins.
                for (var j = start; j <= size; j++)
                {
                    if (matrix.FindDiagonalElement(j) == null)
                    {
                        var twins = CountTwins(matrix, j, ref twin1, ref twin2, size);
                        if (twins == 1)
                        {
                            // Lone twins found, swap columns
                            matrix.SwapColumns(twin2.Column, j);
                            swapped = true;
                        }
                        else if (twins > 1 && !anotherPassNeeded)
                        {
                            anotherPassNeeded = true;
                            start             = j;
                        }
                    }
                }

                // All lone twins are gone, look for zero diagonals with multiple twins.
                if (anotherPassNeeded)
                {
                    for (var j = start; !swapped && j <= size; j++)
                    {
                        if (matrix.FindDiagonalElement(j) == null)
                        {
                            CountTwins(matrix, j, ref twin1, ref twin2, size);
                            matrix.SwapColumns(twin2.Column, j);
                            swapped = true;
                        }
                    }
                }
            }while (anotherPassNeeded);
        }
        /// <inheritdoc/>
        public override Pivot <ISparseMatrixElement <T> > FindPivot(Markowitz <T> markowitz, ISparseMatrix <T> matrix, int eliminationStep, int max)
        {
            markowitz.ThrowIfNull(nameof(markowitz));
            matrix.ThrowIfNull(nameof(matrix));
            if (eliminationStep < 1 || eliminationStep > max)
            {
                return(Pivot <ISparseMatrixElement <T> > .Empty);
            }

            var minMarkowitzProduct = int.MaxValue;
            var numberOfTies        = -1;

            /* Used for debugging along Spice 3f5
             * for (var index = matrix.Size + 1; index > eliminationStep; index--)
             * {
             *  int i = index > matrix.Size ? eliminationStep : index; */
            for (var i = eliminationStep; i <= max; i++)
            {
                // Skip diagonal elements with a Markowitz product worse than already found
                var product = markowitz.Product(i);
                if (product >= minMarkowitzProduct)
                {
                    continue;
                }

                // Get the diagonal item
                var diagonal = matrix.FindDiagonalElement(i);
                if (diagonal == null)
                {
                    continue;
                }

                // Get the magnitude
                var magnitude = markowitz.Magnitude(diagonal.Value);
                if (magnitude <= markowitz.AbsolutePivotThreshold)
                {
                    continue;
                }

                // Well, can't do much better than this can we? (Assuming all the singletons are taken)
                // Note that a singleton can still appear depending on the allowed tolerances!
                if (product == 1)
                {
                    // Find the off-diagonal elements
                    var otherInRow    = diagonal.Right ?? diagonal.Left;
                    var otherInColumn = diagonal.Below ?? diagonal.Above;

                    // Accept diagonal as pivot if diagonal is larger than off-diagonals and
                    // the off-diagonals are placed symmetrically
                    if (otherInRow != null && otherInColumn != null)
                    {
                        if (otherInRow.Column == otherInColumn.Row)
                        {
                            var largest = Math.Max(
                                markowitz.Magnitude(otherInRow.Value),
                                markowitz.Magnitude(otherInColumn.Value));
                            if (magnitude >= largest)
                            {
                                return(new Pivot <ISparseMatrixElement <T> >(diagonal, PivotInfo.Good));
                            }
                        }
                    }
                }

                if (product < minMarkowitzProduct)
                {
                    // We found a diagonal that beats all the previous ones!
                    numberOfTies        = 0;
                    _tiedElements[0]    = diagonal;
                    minMarkowitzProduct = product;
                }
                else
                {
                    if (numberOfTies < _tiedElements.Length - 1)
                    {
                        // Keep track of this diagonal too
                        _tiedElements[++numberOfTies] = diagonal;

                        // This is our heuristic for speeding up pivot searching
                        if (numberOfTies >= minMarkowitzProduct * TiesMultiplier)
                        {
                            break;
                        }
                    }
                }
            }

            // Not even one eligible pivot on the diagonal...
            if (numberOfTies < 0)
            {
                return(Pivot <ISparseMatrixElement <T> > .Empty);
            }

            // Determine which of the tied elements is the best numerical choise
            ISparseMatrixElement <T> chosen = null;
            var maxRatio = 1.0 / markowitz.RelativePivotThreshold;

            for (var i = 0; i <= numberOfTies; i++)
            {
                var diag    = _tiedElements[i];
                var mag     = markowitz.Magnitude(diag.Value);
                var largest = LargestOtherElementInColumn(markowitz, diag, eliminationStep, max);
                var ratio   = largest / mag;
                if (ratio < maxRatio)
                {
                    maxRatio = ratio;
                    chosen   = diag;
                }
            }

            // We don't actually know if the pivot is sub-optimal, but we take the worst case scenario.
            return(chosen != null ? new Pivot <ISparseMatrixElement <T> >(chosen, PivotInfo.Suboptimal) : Pivot <ISparseMatrixElement <T> > .Empty);
        }
Exemple #28
0
        /// <inheritdoc/>
        public override Pivot <ISparseMatrixElement <T> > FindPivot(Markowitz <T> markowitz, ISparseMatrix <T> matrix, int eliminationStep, int max)
        {
            markowitz.ThrowIfNull(nameof(markowitz));
            matrix.ThrowIfNull(nameof(matrix));
            if (eliminationStep < 1 || eliminationStep > max)
            {
                return(Pivot <ISparseMatrixElement <T> > .Empty);
            }

            ISparseMatrixElement <T> chosen = null;
            var    minMarkowitzProduct = long.MaxValue;
            double largestMagnitude = 0.0, acceptedRatio = 0.0;
            ISparseMatrixElement <T> largestElement = null;
            var ties = 0;

            // Start search of matrix on column by column basis
            for (var i = eliminationStep; i <= max; i++)
            {
                // Find an entry point to the interesting part of the column
                var lowest = matrix.GetLastInColumn(i);
                while (lowest != null && lowest.Row > max)
                {
                    lowest = lowest.Above;
                }
                if (lowest == null || lowest.Row < eliminationStep)
                {
                    continue;
                }

                // Find the biggest magnitude in the column for checking valid pivots later
                var largest = 0.0;
                var element = lowest;
                while (element != null && element.Row >= eliminationStep)
                {
                    largest = Math.Max(largest, markowitz.Magnitude(element.Value));
                    element = element.Above;
                }
                if (largest.Equals(0.0))
                {
                    continue;
                }

                // Restart search for a pivot
                element = lowest;
                while (element != null && element.Row >= eliminationStep)
                {
                    // Find the magnitude and Markowitz product
                    var magnitude = markowitz.Magnitude(element.Value);
                    var product   = markowitz.RowCount(element.Row) * markowitz.ColumnCount(element.Column);

                    // In the case no valid pivot is available, at least return the largest element
                    if (magnitude > largestMagnitude)
                    {
                        largestElement   = element;
                        largestMagnitude = magnitude;
                    }

                    // test to see if the element is acceptable as a pivot candidate
                    if (product <= minMarkowitzProduct &&
                        magnitude > markowitz.RelativePivotThreshold * largest &&
                        magnitude > markowitz.AbsolutePivotThreshold)
                    {
                        // Test to see if the element has the lowest Markowitz product yet found,
                        // or whether it is tied with an element found earlier
                        if (product < minMarkowitzProduct)
                        {
                            // Notice strict inequality
                            // This is a new smallest Markowitz product
                            chosen = element;
                            minMarkowitzProduct = product;
                            acceptedRatio       = largest / magnitude;
                            ties = 0;
                        }
                        else
                        {
                            // This case handles Markowitz ties
                            ties++;
                            var ratio = largest / magnitude;
                            if (ratio < acceptedRatio)
                            {
                                chosen        = element;
                                acceptedRatio = ratio;
                            }
                            if (ties >= minMarkowitzProduct * _tiesMultiplier)
                            {
                                return(new Pivot <ISparseMatrixElement <T> >(chosen, PivotInfo.Suboptimal));
                            }
                        }
                    }

                    element = element.Above;
                }
            }

            // If a valid pivot was found, return it
            if (chosen != null)
            {
                return(new Pivot <ISparseMatrixElement <T> >(chosen, PivotInfo.Suboptimal));
            }

            // Else just return the largest element
            if (largestElement == null || largestElement.Value.Equals(default))