Пример #1
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);
        }
Пример #2
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);
            }

            // 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);
        }
Пример #3
0
        /// <summary>
        /// Find the pivot on the diagonal
        /// </summary>
        /// <param name="markowitz">Markowitz</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 (matrix == null)
            {
                throw new ArgumentNullException(nameof(matrix));
            }
            if (markowitz == null)
            {
                throw new ArgumentNullException(nameof(markowitz));
            }
            if (eliminationStep < 1)
            {
                throw new ArgumentException("Invalid elimination step");
            }

            int minMarkowitzProduct           = int.MaxValue;
            MatrixElement <T> chosen          = null;
            double            ratioOfAccepted = 0.0;
            int ties = 0;

            for (int i = eliminationStep; i <= matrix.Size; i++)
            {
                // Skip the diagonal if we already have a better one
                if (markowitz.Product(i) > minMarkowitzProduct)
                {
                    continue;
                }

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

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

                // Check that the pivot is eligible
                double largest = 0.0;
                var    element = diagonal.Below;
                while (element != null)
                {
                    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
                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++;
                    double ratio = largest / magnitude;
                    if (ratio < ratioOfAccepted)
                    {
                        chosen          = diagonal;
                        ratioOfAccepted = ratio;
                    }
                    if (ties >= minMarkowitzProduct * TiesMultiplier)
                    {
                        return(chosen);
                    }
                }
            }

            // The chosen pivot has already been checked for validity
            return(chosen);
        }
        /// <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");
            }

            var minMarkowitzProduct  = int.MaxValue;
            MatrixElement <T> chosen = null;

            for (var i = eliminationStep; i <= matrix.Size; 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.GetDiagonalElement(i);
                if (diagonal == null)
                {
                    continue;
                }

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

                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(diagonal);
                            }
                        }
                    }
                }

                minMarkowitzProduct = markowitz.Product(i);
                chosen = diagonal;
            }

            // No decision was made yet, so check again here
            if (chosen != null)
            {
                // Find the biggest element above and below the pivot
                var element = chosen.Below;
                var largest = 0.0;
                while (element != null)
                {
                    largest = Math.Max(largest, markowitz.Magnitude(element.Value));
                    element = element.Below;
                }
                element = chosen.Above;
                while (element != null && element.Row >= eliminationStep)
                {
                    largest = Math.Max(largest, markowitz.Magnitude(element.Value));
                    element = element.Above;
                }

                // If we can't have stability, then drop the pivot
                if (markowitz.Magnitude(chosen.Value) <= markowitz.RelativePivotThreshold * largest)
                {
                    chosen = null;
                }
            }

            return(chosen);
        }
Пример #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SparseLUSolver{T}"/> class.
 /// </summary>
 /// <param name="magnitude">The magnitude function.</param>
 /// <exception cref="ArgumentNullException">Thrown if <paramref name="magnitude"/> is <c>null</c>.</exception>
 protected SparseLUSolver(Func <T, double> magnitude)
     : base(new SparseMatrix <T>(), new SparseVector <T>())
 {
     Parameters = new Markowitz <T>(magnitude);
     Fillins    = 0;
 }
Пример #6
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))
Пример #7
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);