public DiscreteTimeMarkovChain(ModelCapacity modelCapacity) { var modelSize = modelCapacity.DeriveModelByteSize(_sizeOfState, _sizeOfTransition); StateLabeling = new LabelVector(); ProbabilityMatrix = new SparseDoubleMatrix(modelSize.NumberOfStates + 1, modelSize.NumberOfTransitions); // one additional row for row of initial distribution }
public SparseJacobianEvaluator(int N, Action <double, double[], double[]> f) { variatedX = new double[N]; f_old = new double[N]; f_new = new double[N]; J = new SparseDoubleMatrix(N, N); this.f = f; }
public MarkovDecisionProcess(ModelCapacity modelCapacity) { var modelSize = modelCapacity.DeriveModelByteSize(_sizeOfState, _sizeOfTransition); StateLabeling = new LabelVector(); var numbersOfTransitionsPerState = ((double)modelSize.NumberOfTransitions) / modelSize.NumberOfStates; var numbersOfDistributionsPerState = (long)Math.Ceiling(Math.Sqrt(numbersOfTransitionsPerState)); var numberOfDistributions = modelSize.NumberOfStates * numbersOfDistributionsPerState; RowsWithDistributions = new SparseDoubleMatrix(numberOfDistributions, modelSize.NumberOfTransitions); // need for every distribution one row StateToRowsL = new int[modelSize.NumberOfStates + 1]; // one additional row for initial distributions StateToRowsRowCount = new int[modelSize.NumberOfStates + 1]; // one additional row for initial distributions SetRowOfStateEntriesToInvalid(); }
private SparseDoubleMatrix CreateDerivedMatrix(Dictionary <long, bool> exactlyOneStates, Dictionary <long, bool> exactlyZeroStates) { //Derived matrix is 0-based. Row i is equivalent to the probability distribution of state i (this is not the case for the Markov Chain). var derivedMatrix = new SparseDoubleMatrix(MarkovChain.States, MarkovChain.Transitions + MarkovChain.States); //Transitions+States is a upper limit var enumerator = MarkovChain.GetEnumerator(); for (var sourceState = 0; sourceState < MarkovChain.States; sourceState++) { enumerator.SelectSourceState(sourceState); derivedMatrix.SetRow(sourceState); if (exactlyOneStates.ContainsKey(sourceState) || exactlyZeroStates.ContainsKey(sourceState)) { // only add a self reference entry derivedMatrix.AddColumnValueToCurrentRow(new SparseDoubleMatrix.ColumnValue(sourceState, 1.0)); } else { // if state is neither exactlyOneStates nor exactlyZeroStates, it is a toCalculateState var selfReferenceAdded = false; while (enumerator.MoveNextTransition()) { var columnValueEntry = enumerator.CurrentTransition; var targetState = columnValueEntry.Column; if (targetState == sourceState) { //this implements the removal of the identity matrix derivedMatrix.AddColumnValueToCurrentRow(new SparseDoubleMatrix.ColumnValue(sourceState, columnValueEntry.Value - 1.0)); selfReferenceAdded = true; } else { derivedMatrix.AddColumnValueToCurrentRow(columnValueEntry); } } if (!selfReferenceAdded) { //this implements the removal of the identity matrix (if not already done) derivedMatrix.AddColumnValueToCurrentRow(new SparseDoubleMatrix.ColumnValue(sourceState, -1.0)); } } derivedMatrix.FinishRow(); } return(derivedMatrix); }
private void CreateExemplaryMatrix() { //_matrix = new SparseDoubleMatrix(6, 20); _matrix = new SparseDoubleMatrix(1024, 1024); _matrix.SetRow(0); _matrix.AddColumnValueToCurrentRow(new SparseDoubleMatrix.ColumnValue(0, 1.0)); _matrix.FinishRow(); _matrix.SetRow(1); _matrix.AddColumnValueToCurrentRow(new SparseDoubleMatrix.ColumnValue(1, 2.0)); _matrix.AddColumnValueToCurrentRow(new SparseDoubleMatrix.ColumnValue(2, 3.0)); _matrix.FinishRow(); _matrix.SetRow(2); _matrix.FinishRow(); _matrix.SetRow(3); _matrix.AddColumnValueToCurrentRow(new SparseDoubleMatrix.ColumnValue(0, 4.0)); _matrix.AddColumnValueToCurrentRow(new SparseDoubleMatrix.ColumnValue(4, 5.0)); _matrix.FinishRow(); _matrix.SetRow(4); _matrix.AddColumnValueToCurrentRow(new SparseDoubleMatrix.ColumnValue(4, 6.0)); _matrix.AddColumnValueToCurrentRow(new SparseDoubleMatrix.ColumnValue(3, 7.0)); _matrix.FinishRow(); }
private double[] GaussSeidel(SparseDoubleMatrix derivedMatrix, double[] derivedVector, int iterationsLeft) { var stopwatch = new Stopwatch(); stopwatch.Start(); var stateCount = MarkovChain.States; var resultVector = new double[stateCount]; var fixPointReached = iterationsLeft <= 0; var iterations = 0; //Derived matrix is 0-based. Row i is equivalent to the probability distribution of state i (this is not the case for the Markov Chain). var enumerator = derivedMatrix.GetEnumerator(); for (var i = 0; i < stateCount; i++) { resultVector[i] = 0.0; } while (!fixPointReached) { for (var i = 0; i < stateCount; i++) { var reflexiveEntry = 0.0; var temporaryValue = derivedVector[i]; enumerator.MoveRow(i); while (enumerator.MoveNextColumn()) { var currentEntry = enumerator.CurrentColumnValue.Value; if (currentEntry.Column == i) { reflexiveEntry = currentEntry.Value; } else { temporaryValue -= currentEntry.Value * resultVector[currentEntry.Column]; } } Assert.That(reflexiveEntry != 0.0, "entry must not be 0.0"); resultVector[i] = temporaryValue / reflexiveEntry; } iterationsLeft--; iterations++; if (iterations % 10 == 0) { stopwatch.Stop(); var currentProbability = CalculateFinalProbability(resultVector); _output?.WriteLine($"Completed {iterations} Gauss-Seidel iterations in {stopwatch.Elapsed}. Current probability={currentProbability.ToString(CultureInfo.InvariantCulture)}"); stopwatch.Start(); } if (iterationsLeft <= 0) { fixPointReached = true; } } stopwatch.Stop(); return(resultVector); }
/// <summary> /// Execute predictor-corrector scheme for Nordsieck's method /// </summary> /// <param name="flag"></param> /// <param name="f">Evaluation of the deriatives. First argument is time, second arg are the state variables, and 3rd arg is the array to accomodate the derivatives.</param> /// <param name="denseJacobianEvaluation">Evaluation of the jacobian.</param> /// <param name="sparseJacobianEvaluation">Evaluation of the jacobian as a sparse matrix. Either this or the previous arg must be valid.</param> /// <param name="opts">current options</param> /// <returns>en - current error vector</returns> internal void PredictorCorrectorScheme( ref bool flag, Action <double, double[], double[]> f, Func <double, double[], IROMatrix <double> > denseJacobianEvaluation, Func <double, double[], SparseDoubleMatrix> sparseJacobianEvaluation, GearsBDFOptions opts ) { NordsieckState currstate = this; NordsieckState newstate = this; int n = currstate._xn.Length; VectorMath.Copy(currstate._en, ecurr); VectorMath.Copy(currstate._xn, xcurr); var x0 = currstate._xn; MatrixMath.Copy(currstate._zn, zcurr); // zcurr now is old nordsieck matrix var qcurr = currstate._qn; // current degree var qmax = currstate._qmax; // max degree var dt = currstate._dt; var t = currstate._tn; MatrixMath.Copy(currstate._zn, z0); // save Nordsieck matrix //Tolerance computation factors double Cq = Math.Pow(qcurr + 1, -1.0); double tau = 1.0 / (Cq * Factorial(qcurr) * l[qcurr - 1][qcurr]); int count = 0; double Dq = 0.0, DqUp = 0.0, DqDown = 0.0; double delta = 0.0; //Scaling factors for the step size changing //with new method order q' = q, q + 1, q - 1, respectively double rSame, rUp, rDown; if (null != denseJacobianEvaluation) { var J = denseJacobianEvaluation(t + dt, xcurr); if (J.GetType() != P?.GetType()) { AllocatePMatrixForJacobian(J); } do { MatrixMath.MapIndexed(J, dt * b[qcurr - 1], (i, j, aij, factor) => (i == j ? 1 : 0) - aij * factor, P, Zeros.AllowSkip); // P = Identity - J*dt*b[qcurr-1] VectorMath.Copy(xcurr, xprev); f(t + dt, xcurr, ftdt); MatrixMath.CopyColumn(z0, 1, colExtract); // 1st derivative/dt VectorMath.Map(ftdt, colExtract, ecurr, dt, (ff, c, e, local_dt) => local_dt * ff - c - e, gm); // gm = dt * f(t + dt, xcurr) - z0.GetColumn(1) - ecurr; gaussSolver.SolveDestructive(P, gm, tmpVec1); VectorMath.Add(ecurr, tmpVec1, ecurr); // ecurr = ecurr + P.SolveGE(gm); VectorMath.Map(x0, ecurr, b[qcurr - 1], (x, e, local_b) => x + e * local_b, xcurr); // xcurr = x0 + b[qcurr - 1] * ecurr; //Row dimension is smaller than zcurr has int M_Rows = ecurr.Length; int M_Columns = l[qcurr - 1].Length; //So, "expand" the matrix MatrixMath.MapIndexed(z0, (i, j, z) => z + (i < M_Rows && j < M_Columns ? ecurr[i] * l[qcurr - 1][j] : 0.0d), zcurr); Dq = ToleranceNorm(ecurr, opts.RelativeTolerance, opts.AbsoluteTolerance, xprev); var factor_deltaE = (1.0 / (qcurr + 2) * l[qcurr - 1][qcurr - 1]); VectorMath.Map(ecurr, currstate._en, factor_deltaE, (e, c, factor) => (e - c) * factor, deltaE); // deltaE = (ecurr - currstate.en)*(1.0 / (qcurr + 2) * l[qcurr - 1][qcurr - 1]) DqUp = ToleranceNorm(deltaE, opts.RelativeTolerance, opts.AbsoluteTolerance, xcurr); zcurr.CopyColumn(qcurr - 1, colExtract); DqDown = ToleranceNorm(colExtract, opts.RelativeTolerance, opts.AbsoluteTolerance, xcurr); delta = Dq / (tau / (2 * (qcurr + 2))); count++; } while (delta > 1.0d && count < opts.NumberOfIterations); } else if (null != sparseJacobianEvaluation) { SparseDoubleMatrix J = sparseJacobianEvaluation(t + dt, xcurr); var P = new SparseDoubleMatrix(J.RowCount, J.ColumnCount); do { J.MapSparseIncludingDiagonal((x, i, j) => (i == j ? 1 : 0) - x * dt * b[qcurr - 1], P); VectorMath.Copy(xcurr, xprev); f(t + dt, xcurr, ftdt); MatrixMath.CopyColumn(z0, 1, colExtract); VectorMath.Map(ftdt, colExtract, ecurr, (ff, c, e) => dt * ff - c - e, gm); // gm = dt * f(t + dt, xcurr) - z0.GetColumn(1) - ecurr; gaussSolver.SolveDestructive(P, gm, tmpVec1); VectorMath.Add(ecurr, tmpVec1, ecurr); // ecurr = ecurr + P.SolveGE(gm); VectorMath.Map(x0, ecurr, (x, e) => x + e * b[qcurr - 1], xcurr); // xcurr = x0 + b[qcurr - 1] * ecurr; //Row dimension is smaller than zcurr has int M_Rows = ecurr.Length; int M_Columns = l[qcurr - 1].Length; //So, "expand" the matrix MatrixMath.MapIndexed(z0, (i, j, z) => z + (i < M_Rows && j < M_Columns ? ecurr[i] * l[qcurr - 1][j] : 0.0d), zcurr); Dq = ToleranceNorm(ecurr, opts.RelativeTolerance, opts.AbsoluteTolerance, xprev); var factor_deltaE = (1.0 / (qcurr + 2) * l[qcurr - 1][qcurr - 1]); VectorMath.Map(ecurr, currstate._en, (e, c) => (e - c) * factor_deltaE, deltaE); // deltaE = (ecurr - currstate.en)*(1.0 / (qcurr + 2) * l[qcurr - 1][qcurr - 1]) DqUp = ToleranceNorm(deltaE, opts.RelativeTolerance, opts.AbsoluteTolerance, xcurr); DqDown = ToleranceNorm(zcurr.GetColumn(qcurr - 1), opts.RelativeTolerance, opts.AbsoluteTolerance, xcurr); delta = Dq / (tau / (2 * (qcurr + 2))); count++; } while (delta > 1.0d && count < opts.NumberOfIterations); } else // neither denseJacobianEvaluation nor sparseJacobianEvaluation valid { throw new ArgumentNullException(nameof(denseJacobianEvaluation), "Either denseJacobianEvaluation or sparseJacobianEvaluation must be set!"); } //====================================== var nsuccess = count < opts.NumberOfIterations ? currstate._nsuccess + 1 : 0; if (count < opts.NumberOfIterations) { flag = false; MatrixMath.Copy(zcurr, newstate._zn); zcurr.CopyColumn(0, newstate._xn); VectorMath.Copy(ecurr, newstate._en); } else { flag = true; // MatrixMath.Copy(currstate.zn, newstate.zn); // null operation since currstate and newstate are identical currstate._zn.CopyColumn(0, newstate._xn); VectorMath.Copy(currstate._en, newstate._en); // null operation since currstate and newstate are identical } //Compute step size scaling factors rUp = 0.0; if (currstate._qn < currstate._qmax) { rUp = rUp = 1.0 / 1.4 / (Math.Pow(DqUp, 1.0 / (qcurr + 2)) + 1e-6); } rSame = 1.0 / 1.2 / (Math.Pow(Dq, 1.0 / (qcurr + 1)) + 1e-6); rDown = 0.0; if (currstate._qn > 1) { rDown = 1.0 / 1.3 / (Math.Pow(DqDown, 1.0 / (qcurr)) + 1e-6); } //====================================== _nsuccess = nsuccess >= _qn ? 0 : nsuccess; //Step size scale operations if (rSame >= rUp) { if (rSame <= rDown && nsuccess >= _qn && _qn > 1) { _qn = _qn - 1; _Dq = DqDown; for (int i = 0; i < n; i++) { for (int j = newstate._qn + 1; j < qmax + 1; j++) { _zn[i, j] = 0.0; } } nsuccess = 0; _rFactor = rDown; } else { // _qn = _qn; _Dq = Dq; _rFactor = rSame; } } else { if (rUp >= rDown) { if (rUp >= rSame && nsuccess >= _qn && _qn < _qmax) { _qn = _qn + 1; _Dq = DqUp; _rFactor = rUp; nsuccess = 0; } else { // _qn = _qn; _Dq = Dq; _rFactor = rSame; } } else { if (nsuccess >= _qn && _qn > 1) { _qn = _qn - 1; _Dq = DqDown; for (int i = 0; i < n; i++) { for (int j = newstate._qn + 1; j < qmax + 1; j++) { _zn[i, j] = 0.0; } } nsuccess = 0; _rFactor = rDown; } else { // _qn = _qn; _Dq = Dq; _rFactor = rSame; } } } _dt = dt; _tn = t; }