Exemple #1
0
        public double[] GetOtherRHSComponents(ISolverSubdomain subdomain, IVector <double> currentSolution)
        {
            //// u[id]: old solution
            //// v[id]: current solution
            //// vv: old acceleration
            //// v2: current acceleration
            //// v1: current velocity
            ////double vv = v2[id].Data[j];
            ////v2[id].Data[j] = a0 * (v[id].Data[j] - u[id].Data[j]) - a2 * v1[id].Data[j] - a3 * vv;
            ////v1[id].Data[j] += a6 * vv + a7 * v2[id].Data[j];

            //int id = subdomain.ID;
            //Vector<double> currentAcceleration = new Vector<double>(subdomain.Solution.Length);
            //Vector<double> currentVelocity = new Vector<double>(subdomain.Solution.Length);
            //Vector<double> uu = new Vector<double>(subdomain.Solution.Length);
            //Vector<double> uc = new Vector<double>(subdomain.Solution.Length);
            //for (int j = 0; j < subdomain.RHS.Length; j++)
            //{
            //    currentAcceleration.Data[j] = a0 * (currentSolution[j] - v[id].Data[j]) - a2 * v1[id].Data[j] - a3 * v2[id].Data[j];
            //    currentVelocity.Data[j] = v1[id].Data[j] + a6 * v2[id].Data[j] + a7 * currentAcceleration.Data[j];
            //    uu.Data[j] = a0 * currentSolution[j] + a2 * currentVelocity.Data[j] + a3 * currentAcceleration.Data[j];
            //    uc.Data[j] = a1 * currentSolution[j] + a4 * currentVelocity.Data[j] + a5 * currentAcceleration.Data[j];
            //}

            //Vector<double> tempResult = new Vector<double>(subdomain.Solution.Length);
            //Vector<double> result = new Vector<double>(subdomain.Solution.Length);
            //provider.MassMatrixVectorProduct(subdomain, uu, tempResult.Data);
            //result.Add(tempResult);

            //provider.DampingMatrixVectorProduct(subdomain, uc, tempResult.Data);
            //result.Add(tempResult);

            //return result.Data;

            Vector <double> result     = new Vector <double>(subdomain.Solution.Length);
            Vector <double> temp       = new Vector <double>(subdomain.Solution.Length);
            Vector <double> tempResult = new Vector <double>(subdomain.Solution.Length);

            //Vector<double> uu = new Vector<double>(subdomain.Solution.Length);
            //Vector<double> uc = new Vector<double>(subdomain.Solution.Length);
            //int id = subdomain.ID;
            //for (int j = 0; j < subdomain.RHS.Length; j++)
            //{
            //    uu.Data[j] = -a0 * (v[id].Data[j] - currentSolution[j]) - a2 * v1[id].Data[j] - a3 * v2[id].Data[j];
            //    uc.Data[j] = -a1 * (v[id].Data[j] - currentSolution[j]) - a4 * v1[id].Data[j] - a5 * v2[id].Data[j];
            //}
            //provider.MassMatrixVectorProduct(subdomain, uu, tempResult.Data);
            //result.Add(tempResult);
            //provider.DampingMatrixVectorProduct(subdomain, uc, tempResult.Data);
            //result.Add(tempResult);

            ////CalculateRHSImplicit(subdomain, result.Data, false);
            ////result.Scale(-1d);
            currentSolution.CopyTo(temp.Data, 0);
            temp.Scale(a0);
            provider.MassMatrixVectorProduct(subdomain, temp, tempResult.Data);
            result.Add(tempResult);

            currentSolution.CopyTo(temp.Data, 0);
            temp.Scale(a1);
            provider.DampingMatrixVectorProduct(subdomain, temp, tempResult.Data);
            result.Add(tempResult);

            return(result.Data);
        }
Exemple #2
0
        /// <summary>
        /// Resolves the variables.
        /// </summary>
        public void Solve()
        {
            BuildSolver();

            // Solve for real this time
            var    iterations      = 0;
            double error           = 1.0;
            bool   needsReordering = true;

            while (error > 1e-9)
            {
                // Build the matrix
                _solver.Reset();
                foreach (var eq in _map)
                {
                    eq.Key.Value = _solution[eq.Value];
                }
                foreach (var eq in _equations)
                {
                    eq.Value.Update();
                    eq.Value.Apply(1.0, null);
                }
                iterations++;

                // Order and factor
                int steps;
                _solver.Degeneracy = 0;
                if (needsReordering)
                {
                    steps           = _solver.OrderAndFactor();
                    needsReordering = false;
                }
                else
                {
                    if (!_solver.Factor())
                    {
                        needsReordering = true;
                        continue;
                    }
                    else
                    {
                        steps = _solution.Length;
                    }
                }

                // Update the solution
                if (LogInfo)
                {
                    Console.WriteLine($"- Iteration {iterations} ({steps}/{_solver.Size} rows factored)");
                    if (steps < _solution.Length)
                    {
                        for (var i = steps + 1; i <= _solution.Length; i++)
                        {
                            var ext = _solver.InternalToExternal(new MatrixLocation(i, i));
                            Console.WriteLine($"    (Could not solve equation for {_map.Reverse(ext.Row)} or unknown {_map.Reverse(ext.Column)})");
                        }
                    }
                }
                _solver.Degeneracy = _solver.Size - steps;
                _solution.CopyTo(_oldSolution);
                _solver.Solve(_solution);
                if (LogInfo)
                {
                    foreach (var eq in _map)
                    {
                        var msg = $"    {eq.Key} = {_solution[eq.Value]} (last was {_oldSolution[eq.Value]})";
                        if (Math.Abs(_solution[eq.Value] - _oldSolution[eq.Value]) > 1e-6)
                        {
                            Utility.Error(msg);
                        }
                        else
                        {
                            Console.WriteLine(msg);
                        }
                    }
                }

                // find the maximum error
                error = 0.0;
                for (var i = 1; i <= _map.Count; i++)
                {
                    // Detect infinity and NaN
                    var uk = _map.Reverse(i);
                    if (_lambdas.Contains(uk))
                    {
                        // We don't particularly care of our Lagrange multipliers, we will just make sure that they don't cause problems later on
                        // The thing is that lagrange multipliers can become undefined if a minimization and a constraint
                        // are leading to the same solution. In that case we get lamba*0=0 and the lagrange multiplier becomes undefined.
                        if (double.IsNaN(_solution[i]) || double.IsPositiveInfinity(_solution[i]) || _solution[i] > 1e6)
                        {
                            _solution[i] = 1e6; // Just a value to get through the next iteration
                        }
                        else if (double.IsNegativeInfinity(_solution[i]) || _solution[i] < -1e6)
                        {
                            _solution[i] = -1e6;
                        }
                    }
                    else
                    {
                        // For any other unknown, we do want to know how far we're off
                        double e;
                        switch (uk.Type)
                        {
                        case UnknownTypes.Length:
                            e = Math.Abs(_solution[i] - _oldSolution[i]);

                            // Add some randomization to avoid invalid "local minimum" solutions
                            if (_solution[i] < 0)
                            {
                                _solution[i] = 1e-6 / (_rnd.NextDouble() + 1);
                            }
                            error = Math.Max(error, e);
                            break;

                        case UnknownTypes.Scale:
                            e = Math.Abs(_solution[i] - _oldSolution[i]);

                            // Add some random variation to stay away from zero to avoid invalid "local minimum" solutions
                            if (_solution[i].IsZero())
                            {
                                var r = _rnd.NextDouble();
                                if (r > 0.5)
                                {
                                    _solution[i] = 1e-3 / (r + 1.0);
                                }
                                else
                                {
                                    _solution[i] = -1e-3 / (r + 1.0);
                                }
                            }
                            error = Math.Max(error, e);
                            break;

                        default:
                            e     = Math.Abs(_solution[i] - _oldSolution[i]);
                            error = Math.Max(error, e);
                            break;
                        }
                    }
                }

                // Take a partial step if necessary to keep our inequalities greater than their minimum value
                double alpha = 1;
                foreach (var m in _minimum)
                {
                    if (_map.TryGet(m.Key, out var index))
                    {
                        if (_solution[index] < m.Value)
                        {
                            alpha = Math.Min(alpha, (m.Value - _oldSolution[index]) / (_solution[index] - _oldSolution[index]));
                            error = 1;
                        }
                        if (_solution[index] <= m.Value)
                        {
                            _solution[index] = m.Value + 1e-9;
                        }
                    }
                }
                if (LogInfo)
                {
                    Console.WriteLine($"Alpha = {alpha}");
                }
                for (var i = 1; i <= _map.Count; i++)
                {
                    _solution[i] = _solution[i] * alpha + _oldSolution[i] * (1 - alpha);
                }

                if (error < 1e-6)
                {
                    break;
                }
                if (iterations > 100)
                {
                    if (LogInfo)
                    {
                        Console.WriteLine("Could not converge...");
                    }
                    Warn(this, new WarningEventArgs("Could not converge to a solution."));
                    return;
                }
            }
        }
Exemple #3
0
        public void Solve(IVector <double> f, double[] result)
        {
            //var e = DateTime.Now;
            SkylineMatrix2D <T> K = this;

            if (!K.isFactorized)
            {
                throw new InvalidOperationException("Cannot solve if matrix is not factorized.");
            }
            if (!(typeof(T) == typeof(double)))
            {
                throw new InvalidOperationException("Cannot solve for types other than double");
            }
            if (K.Rows != f.Length)
            {
                throw new InvalidOperationException("Matrix and vector size mismatch.");
            }
            double[] d = K.Data as double[];
            //double[] result = new double[K.Rows];
            f.CopyTo(result, 0);

            // RHS vector reduction
            int n;

            for (n = 0; n < K.Rows; n++)
            {
                int KL = K.RowIndex[n] + 1;
                int KU = K.RowIndex[n + 1] - 1;
                if (KU >= KL)
                {
                    int    k = n;
                    double C = 0;
                    for (int KK = KL; KK <= KU; KK++)
                    {
                        k--;
                        C += d[KK] * result[k];
                    }
                    result[n] -= C;
                }
            }

            // Back substitution
            for (n = 0; n < K.Rows; n++)
            {
                result[n] /= d[K.RowIndex[n]];
            }

            n = K.Rows - 1;
            for (int l = 1; l < K.Rows; l++)
            {
                int KL = K.RowIndex[n] + 1;
                int KU = K.RowIndex[n + 1] - 1;
                if (KU >= KL)
                {
                    int k = n;
                    for (int KK = KL; KK <= KU; KK++)
                    {
                        k--;
                        result[k] -= d[KK] * result[n];
                    }
                }
                n--;
            }
            //var x = new List<TimeSpan>();
            //x.Add(DateTime.Now - e);
        }