コード例 #1
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>
        /// <returns>
        /// The pivot element, or null if no pivot was found.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// markowitz
        /// or
        /// matrix
        /// </exception>
        /// <exception cref="ArgumentException">Invalid elimination step</exception>
        public override MatrixElement <T> FindPivot(Markowitz <T> markowitz, SparseMatrix <T> matrix, int eliminationStep)
        {
            if (markowitz == null)
            {
                throw new ArgumentNullException(nameof(markowitz));
            }
            if (matrix == null)
            {
                throw new ArgumentNullException(nameof(matrix));
            }
            if (eliminationStep < 1)
            {
                throw new ArgumentException("Invalid elimination step");
            }

            // No singletons left, so don't bother
            if (markowitz.Singletons == 0)
            {
                return(null);
            }

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

            for (var i = matrix.Size + 1; i >= eliminationStep; i--)
            {
                // First check the current pivot, else
                // search from last to first as it tends to push the higher markowitz
                // products downwards.
                index = i > matrix.Size ? 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
                MatrixElement <T> chosen;
                if (markowitz.ColumnCount(index) == 0)
                {
                    // The last element in the column is the singleton element!
                    chosen = matrix.GetLastInColumn(index);

                    // Check if it is a valid pivot
                    var magnitude = markowitz.Magnitude(chosen.Value);
                    if (magnitude > markowitz.AbsolutePivotThreshold)
                    {
                        return(chosen);
                    }
                }

                // 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)
                    {
                        largest = Math.Max(largest, markowitz.Magnitude(element.Value));
                        element = element.Below;
                    }

                    // Check if the pivot is valid
                    var magnitude = markowitz.Magnitude(chosen.Value);
                    if (magnitude > markowitz.AbsolutePivotThreshold &&
                        magnitude > markowitz.RelativePivotThreshold * largest)
                    {
                        return(chosen);
                    }
                }

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

            // All singletons were unacceptable...
            return(null);
        }
コード例 #2
0
        /// <summary>
        /// Search the entire matrix for a suitable pivot
        /// In order to preserve sparsity, Markowitz counts are used to find the largest valid
        /// pivot with the smallest number of elements.
        /// </summary>
        /// <param name="markowitz">Markowitz object</param>
        /// <param name="matrix">Matrix</param>
        /// <param name="eliminationStep">Step</param>
        /// <returns></returns>
        public override MatrixElement <T> FindPivot(Markowitz <T> markowitz, SparseMatrix <T> matrix, int eliminationStep)
        {
            if (markowitz == null)
            {
                throw new ArgumentNullException(nameof(markowitz));
            }
            if (matrix == null)
            {
                throw new ArgumentNullException(nameof(matrix));
            }
            if (eliminationStep < 1)
            {
                throw new ArgumentException("Invalid elimination step");
            }

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

            // Start search of matrix on column by column basis
            for (int i = eliminationStep; i <= matrix.Size; i++)
            {
                // Find the biggest magnitude in the column for checking valid pivots later
                double largest = 0.0;
                var    element = matrix.GetLastInColumn(i);
                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 = matrix.GetLastInColumn(i);
                while (element != null && element.Row >= eliminationStep)
                {
                    // Find the magnitude and Markowitz product
                    double magnitude = markowitz.Magnitude(element.Value);
                    int    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++;
                            double ratio = largest / magnitude;
                            if (ratio < acceptedRatio)
                            {
                                chosen        = element;
                                acceptedRatio = ratio;
                            }
                            if (ties >= minMarkowitzProduct * TiesMultiplier)
                            {
                                return(chosen);
                            }
                        }
                    }

                    element = element.Above;
                }
            }

            // If a valid pivot was found, return it
            if (chosen != null)
            {
                return(chosen);
            }

            // Singular matrix
            // If we can't find it while searching the entire matrix, then we definitely have a singular matrix...
            if (largestElement == null || largestElement.Value.Equals(0.0))
            {
                throw new SingularException(eliminationStep);
            }
            return(largestElement);
        }
コード例 #3
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))