/** * Compute next=state probabilities. i.e. compute the probability of being in a state in {@code * target} in the next step. * * @param stpg The STPG * @param target Target states * @param min1 Min or max probabilities for player 1 (true=lower bound, false=upper bound) * @param min2 Min or max probabilities for player 2 (true=min, false=max) */ public ModelCheckerResult computeNextProbs(STPG stpg, BitSet target, boolean min1, boolean min2) throws PrismException { ModelCheckerResult res = null; int n; double soln[], soln2[]; long timer; timer = System.currentTimeMillis(); // Store num states n = stpg.getNumStates(); // Create/initialise solution vector(s) soln = Utils.bitsetToDoubleArray(target, n); soln2 = new double[n]; // Next-step probabilities stpg.mvMultMinMax(soln, min1, min2, soln2, null, false, null); // Return results res = new ModelCheckerResult(); res.soln = soln2; res.numIters = 1; res.timeTaken = timer / 1000.0; return res; }
/** * Compute bounded reachability/until probabilities. i.e. compute the min/max probability of * reaching a state in {@code target}, within time t, and while remaining in states in @{code * remain}. * * @param ctmdp The CTMDP * @param remain Remain in these states (optional: null means "all") * @param target Target states * @param t: Time bound * @param min Min or max probabilities (true=min, false=max) * @param init: Initial solution vector - pass null for default * @param results: Optional array of size b+1 to store (init state) results for each step (null if * unused) */ public ModelCheckerResult computeBoundedReachProbsOld( CTMDP ctmdp, BitSet remain, BitSet target, double t, boolean min, double init[], double results[]) throws PrismException { // TODO: implement until ModelCheckerResult res = null; int i, n, iters; double soln[], soln2[], tmpsoln[], sum[]; long timer; // Fox-Glynn stuff FoxGlynn fg; int left, right; double q, qt, weights[], totalWeight; // Start bounded probabilistic reachability timer = System.currentTimeMillis(); mainLog.println("Starting time-bounded probabilistic reachability..."); // Store num states n = ctmdp.getNumStates(); // Get uniformisation rate; do Fox-Glynn q = 99; // ctmdp.unif; qt = q * t; mainLog.println("\nUniformisation: q.t = " + q + " x " + t + " = " + qt); fg = new FoxGlynn(qt, 1e-300, 1e+300, termCritParam / 8.0); left = fg.getLeftTruncationPoint(); right = fg.getRightTruncationPoint(); if (right < 0) { throw new PrismException("Overflow in Fox-Glynn computation (time bound too big?)"); } weights = fg.getWeights(); totalWeight = fg.getTotalWeight(); for (i = left; i <= right; i++) { weights[i - left] /= totalWeight; } mainLog.println("Fox-Glynn: left = " + left + ", right = " + right); // Create solution vector(s) soln = new double[n]; soln2 = (init == null) ? new double[n] : init; sum = new double[n]; // Initialise solution vectors. Use passed in initial vector, if present if (init != null) { for (i = 0; i < n; i++) soln[i] = soln2[i] = target.get(i) ? 1.0 : init[i]; } else { for (i = 0; i < n; i++) soln[i] = soln2[i] = target.get(i) ? 1.0 : 0.0; } for (i = 0; i < n; i++) sum[i] = 0.0; // If necessary, do 0th element of summation (doesn't require any matrix powers) if (left == 0) for (i = 0; i < n; i++) sum[i] += weights[0] * soln[i]; // Start iterations iters = 1; while (iters <= right) { // Matrix-vector multiply and min/max ops ctmdp.mvMultMinMax(soln, min, soln2, target, true, null); // Since is globally uniform, can do this? and more? for (i = 0; i < n; i++) soln2[i] /= q; // Store intermediate results if required // TODO? // Swap vectors for next iter tmpsoln = soln; soln = soln2; soln2 = tmpsoln; // Add to sum if (iters >= left) { for (i = 0; i < n; i++) sum[i] += weights[iters - left] * soln[i]; } iters++; } // Print vector (for debugging) mainLog.println(sum); // Finished bounded probabilistic reachability timer = System.currentTimeMillis() - timer; mainLog.print("Time-bounded probabilistic reachability (" + (min ? "min" : "max") + ")"); mainLog.println(" took " + iters + " iters and " + timer / 1000.0 + " seconds."); // Return results res = new ModelCheckerResult(); res.soln = sum; res.lastSoln = soln2; res.numIters = iters; res.timeTaken = timer / 1000.0; return res; }
/** * Compute expected reachability rewards. i.e. compute the min/max reward accumulated to reach a * state in {@code target}. * * @param stpg The STPG * @param rewards The rewards * @param target Target states * @param min1 Min or max rewards for player 1 (true=min, false=max) * @param min2 Min or max rewards for player 2 (true=min, false=max) * @param init Optionally, an initial solution vector (may be overwritten) * @param known Optionally, a set of states for which the exact answer is known Note: if 'known' * is specified (i.e. is non-null, 'init' must also be given and is used for the exact values. */ public ModelCheckerResult computeReachRewards( STPG stpg, STPGRewards rewards, BitSet target, boolean min1, boolean min2, double init[], BitSet known) throws PrismException { ModelCheckerResult res = null; BitSet inf; int i, n, numTarget, numInf; long timer, timerProb1; // Start expected reachability timer = System.currentTimeMillis(); if (verbosity >= 1) mainLog.println("\nStarting expected reachability..."); // Check for deadlocks in non-target state (because breaks e.g. prob1) stpg.checkForDeadlocks(target); // Store num states n = stpg.getNumStates(); // Optimise by enlarging target set (if more info is available) if (init != null && known != null) { BitSet targetNew = new BitSet(n); for (i = 0; i < n; i++) { targetNew.set(i, target.get(i) || (known.get(i) && init[i] == 0.0)); } target = targetNew; } // Precomputation (not optional) timerProb1 = System.currentTimeMillis(); inf = prob1(stpg, null, target, !min1, !min2); inf.flip(0, n); timerProb1 = System.currentTimeMillis() - timerProb1; // Print results of precomputation numTarget = target.cardinality(); numInf = inf.cardinality(); if (verbosity >= 1) mainLog.println( "target=" + numTarget + ", inf=" + numInf + ", rest=" + (n - (numTarget + numInf))); // Compute rewards switch (solnMethod) { case VALUE_ITERATION: res = computeReachRewardsValIter(stpg, rewards, target, inf, min1, min2, init, known); break; default: throw new PrismException("Unknown STPG solution method " + solnMethod); } // Finished expected reachability timer = System.currentTimeMillis() - timer; if (verbosity >= 1) mainLog.println("Expected reachability took " + timer / 1000.0 + " seconds."); // Update time taken res.timeTaken = timer / 1000.0; res.timePre = timerProb1 / 1000.0; return res; }
/** * Compute bounded reachability/until probabilities. i.e. compute the min/max probability of * reaching a state in {@code target}, within k steps, and while remaining in states in @{code * remain}. * * @param stpg The STPG * @param remain Remain in these states (optional: null means "all") * @param target Target states * @param k Bound * @param min1 Min or max probabilities for player 1 (true=lower bound, false=upper bound) * @param min2 Min or max probabilities for player 2 (true=min, false=max) * @param init Initial solution vector - pass null for default * @param results Optional array of size k+1 to store (init state) results for each step (null if * unused) */ public ModelCheckerResult computeBoundedReachProbs( STPG stpg, BitSet remain, BitSet target, int k, boolean min1, boolean min2, double init[], double results[]) throws PrismException { // TODO: implement until ModelCheckerResult res = null; int i, n, iters; double soln[], soln2[], tmpsoln[]; long timer; // Start bounded probabilistic reachability timer = System.currentTimeMillis(); if (verbosity >= 1) mainLog.println("\nStarting bounded probabilistic reachability..."); // Store num states n = stpg.getNumStates(); // Create solution vector(s) soln = new double[n]; soln2 = (init == null) ? new double[n] : init; // Initialise solution vectors. Use passed in initial vector, if present if (init != null) { for (i = 0; i < n; i++) soln[i] = soln2[i] = target.get(i) ? 1.0 : init[i]; } else { for (i = 0; i < n; i++) soln[i] = soln2[i] = target.get(i) ? 1.0 : 0.0; } // Store intermediate results if required // (compute min/max value over initial states for first step) if (results != null) { results[0] = Utils.minMaxOverArraySubset(soln2, stpg.getInitialStates(), min2); } // Start iterations iters = 0; while (iters < k) { iters++; // Matrix-vector multiply and min/max ops stpg.mvMultMinMax(soln, min1, min2, soln2, target, true, null); // Store intermediate results if required // (compute min/max value over initial states for this step) if (results != null) { results[iters] = Utils.minMaxOverArraySubset(soln2, stpg.getInitialStates(), min2); } // Swap vectors for next iter tmpsoln = soln; soln = soln2; soln2 = tmpsoln; } // Print vector (for debugging) // mainLog.println(soln); // Finished bounded probabilistic reachability timer = System.currentTimeMillis() - timer; if (verbosity >= 1) { mainLog.print( "Bounded probabilistic reachability (" + (min1 ? "min" : "max") + (min2 ? "min" : "max") + ")"); mainLog.println(" took " + iters + " iterations and " + timer / 1000.0 + " seconds."); } // Return results res = new ModelCheckerResult(); res.soln = soln; res.lastSoln = soln2; res.numIters = iters; res.timeTaken = timer / 1000.0; res.timePre = 0.0; return res; }
/** * Compute reachability probabilities using Gauss-Seidel. * * @param stpg The STPG * @param no Probability 0 states * @param yes Probability 1 states * @param min1 Min or max probabilities for player 1 (true=lower bound, false=upper bound) * @param min2 Min or max probabilities for player 2 (true=min, false=max) * @param init Optionally, an initial solution vector (will be overwritten) * @param known Optionally, a set of states for which the exact answer is known Note: if 'known' * is specified (i.e. is non-null, 'init' must also be given and is used for the exact values. */ protected ModelCheckerResult computeReachProbsGaussSeidel( STPG stpg, BitSet no, BitSet yes, boolean min1, boolean min2, double init[], BitSet known) throws PrismException { ModelCheckerResult res; BitSet unknown; int i, n, iters; double soln[], initVal, maxDiff; boolean done; long timer; // Start value iteration timer = System.currentTimeMillis(); if (verbosity >= 1) mainLog.println( "Starting value iteration (" + (min1 ? "min" : "max") + (min2 ? "min" : "max") + ")..."); // Store num states n = stpg.getNumStates(); // Create solution vector soln = (init == null) ? new double[n] : init; // Initialise solution vector. Use (where available) the following in order of preference: // (1) exact answer, if already known; (2) 1.0/0.0 if in yes/no; (3) passed in initial value; // (4) initVal // where initVal is 0.0 or 1.0, depending on whether we converge from below/above. initVal = (valIterDir == ValIterDir.BELOW) ? 0.0 : 1.0; if (init != null) { if (known != null) { for (i = 0; i < n; i++) soln[i] = known.get(i) ? init[i] : yes.get(i) ? 1.0 : no.get(i) ? 0.0 : init[i]; } else { for (i = 0; i < n; i++) soln[i] = yes.get(i) ? 1.0 : no.get(i) ? 0.0 : init[i]; } } else { for (i = 0; i < n; i++) soln[i] = yes.get(i) ? 1.0 : no.get(i) ? 0.0 : initVal; } // Determine set of states actually need to compute values for unknown = new BitSet(); unknown.set(0, n); unknown.andNot(yes); unknown.andNot(no); if (known != null) unknown.andNot(known); // Start iterations iters = 0; done = false; while (!done && iters < maxIters) { iters++; // Matrix-vector multiply and min/max ops maxDiff = stpg.mvMultGSMinMax(soln, min1, min2, unknown, false, termCrit == TermCrit.ABSOLUTE); // Check termination done = maxDiff < termCritParam; } // Finished Gauss-Seidel timer = System.currentTimeMillis() - timer; if (verbosity >= 1) { mainLog.print("Value iteration (" + (min1 ? "min" : "max") + (min2 ? "min" : "max") + ")"); mainLog.println(" took " + iters + " iterations and " + timer / 1000.0 + " seconds."); } // Non-convergence is an error (usually) if (!done && errorOnNonConverge) { String msg = "Iterative method did not converge within " + iters + " iterations."; msg += "\nConsider using a different numerical method or increasing the maximum number of iterations"; throw new PrismException(msg); } // Return results res = new ModelCheckerResult(); res.soln = soln; res.numIters = iters; res.timeTaken = timer / 1000.0; return res; }
/** * Compute reachability probabilities using value iteration. * * @param stpg The STPG * @param no Probability 0 states * @param yes Probability 1 states * @param min1 Min or max probabilities for player 1 (true=lower bound, false=upper bound) * @param min2 Min or max probabilities for player 2 (true=min, false=max) * @param init Optionally, an initial solution vector (will be overwritten) * @param known Optionally, a set of states for which the exact answer is known Note: if 'known' * is specified (i.e. is non-null, 'init' must also be given and is used for the exact values. */ protected ModelCheckerResult computeReachProbsValIter( STPG stpg, BitSet no, BitSet yes, boolean min1, boolean min2, double init[], BitSet known) throws PrismException { ModelCheckerResult res = null; BitSet unknown; int i, n, iters; double soln[], soln2[], tmpsoln[], initVal; int adv[] = null; boolean genAdv, done; long timer; // Are we generating an optimal adversary? genAdv = exportAdv; // Start value iteration timer = System.currentTimeMillis(); if (verbosity >= 1) mainLog.println( "Starting value iteration (" + (min1 ? "min" : "max") + (min2 ? "min" : "max") + ")..."); // Store num states n = stpg.getNumStates(); // Create solution vector(s) soln = new double[n]; soln2 = (init == null) ? new double[n] : init; // Initialise solution vectors. Use (where available) the following in order of preference: // (1) exact answer, if already known; (2) 1.0/0.0 if in yes/no; (3) passed in initial value; // (4) initVal // where initVal is 0.0 or 1.0, depending on whether we converge from below/above. initVal = (valIterDir == ValIterDir.BELOW) ? 0.0 : 1.0; if (init != null) { if (known != null) { for (i = 0; i < n; i++) soln[i] = soln2[i] = known.get(i) ? init[i] : yes.get(i) ? 1.0 : no.get(i) ? 0.0 : init[i]; } else { for (i = 0; i < n; i++) soln[i] = soln2[i] = yes.get(i) ? 1.0 : no.get(i) ? 0.0 : init[i]; } } else { for (i = 0; i < n; i++) soln[i] = soln2[i] = yes.get(i) ? 1.0 : no.get(i) ? 0.0 : initVal; } // Determine set of states actually need to compute values for unknown = new BitSet(); unknown.set(0, n); unknown.andNot(yes); unknown.andNot(no); if (known != null) unknown.andNot(known); // Create/initialise adversary storage if (genAdv) { adv = new int[n]; for (i = 0; i < n; i++) { adv[i] = -1; } } // Start iterations iters = 0; done = false; while (!done && iters < maxIters) { iters++; // Matrix-vector multiply and min/max ops stpg.mvMultMinMax(soln, min1, min2, soln2, unknown, false, genAdv ? adv : null); // Check termination done = PrismUtils.doublesAreClose(soln, soln2, termCritParam, termCrit == TermCrit.ABSOLUTE); // Swap vectors for next iter tmpsoln = soln; soln = soln2; soln2 = tmpsoln; } // Finished value iteration timer = System.currentTimeMillis() - timer; if (verbosity >= 1) { mainLog.print("Value iteration (" + (min1 ? "min" : "max") + (min2 ? "min" : "max") + ")"); mainLog.println(" took " + iters + " iterations and " + timer / 1000.0 + " seconds."); } // Non-convergence is an error (usually) if (!done && errorOnNonConverge) { String msg = "Iterative method did not converge within " + iters + " iterations."; msg += "\nConsider using a different numerical method or increasing the maximum number of iterations"; throw new PrismException(msg); } // Print adversary if (genAdv) { PrismLog out = new PrismFileLog(exportAdvFilename); for (i = 0; i < n; i++) { out.println(i + " " + (adv[i] != -1 ? stpg.getAction(i, adv[i]) : "-")); } out.println(); } // Return results res = new ModelCheckerResult(); res.soln = soln; res.numIters = iters; res.timeTaken = timer / 1000.0; return res; }
/** * Compute reachability/until probabilities. i.e. compute the min/max probability of reaching a * state in {@code target}, while remaining in those in @{code remain}. * * @param stpg The STPG * @param remain Remain in these states (optional: null means "all") * @param target Target states * @param min1 Min or max probabilities for player 1 (true=lower bound, false=upper bound) * @param min2 Min or max probabilities for player 2 (true=min, false=max) * @param init Optionally, an initial solution vector (may be overwritten) * @param known Optionally, a set of states for which the exact answer is known Note: if 'known' * is specified (i.e. is non-null, 'init' must also be given and is used for the exact values. */ public ModelCheckerResult computeReachProbs( STPG stpg, BitSet remain, BitSet target, boolean min1, boolean min2, double init[], BitSet known) throws PrismException { ModelCheckerResult res = null; BitSet no, yes; int i, n, numYes, numNo; long timer, timerProb0, timerProb1; boolean genAdv; // Check for some unsupported combinations if (solnMethod == SolnMethod.VALUE_ITERATION && valIterDir == ValIterDir.ABOVE && !(precomp && prob0)) { throw new PrismException( "Precomputation (Prob0) must be enabled for value iteration from above"); } // Are we generating an optimal adversary? genAdv = exportAdv; // Start probabilistic reachability timer = System.currentTimeMillis(); if (verbosity >= 1) mainLog.println("\nStarting probabilistic reachability..."); // Check for deadlocks in non-target state (because breaks e.g. prob1) stpg.checkForDeadlocks(target); // Store num states n = stpg.getNumStates(); // Optimise by enlarging target set (if more info is available) if (init != null && known != null) { BitSet targetNew = new BitSet(n); for (i = 0; i < n; i++) { targetNew.set(i, target.get(i) || (known.get(i) && init[i] == 1.0)); } target = targetNew; } // Precomputation timerProb0 = System.currentTimeMillis(); if (precomp && prob0) { no = prob0(stpg, remain, target, min1, min2); } else { no = new BitSet(); } timerProb0 = System.currentTimeMillis() - timerProb0; timerProb1 = System.currentTimeMillis(); if (precomp && prob1 && !genAdv) { yes = prob1(stpg, remain, target, min1, min2); } else { yes = (BitSet) target.clone(); } timerProb1 = System.currentTimeMillis() - timerProb1; // Print results of precomputation numYes = yes.cardinality(); numNo = no.cardinality(); if (verbosity >= 1) mainLog.println( "target=" + target.cardinality() + ", yes=" + numYes + ", no=" + numNo + ", maybe=" + (n - (numYes + numNo))); // Compute probabilities switch (solnMethod) { case VALUE_ITERATION: res = computeReachProbsValIter(stpg, no, yes, min1, min2, init, known); break; case GAUSS_SEIDEL: res = computeReachProbsGaussSeidel(stpg, no, yes, min1, min2, init, known); break; default: throw new PrismException("Unknown STPG solution method " + solnMethod); } // Finished probabilistic reachability timer = System.currentTimeMillis() - timer; if (verbosity >= 1) mainLog.println("Probabilistic reachability took " + timer / 1000.0 + " seconds."); // Update time taken res.timeTaken = timer / 1000.0; res.timeProb0 = timerProb0 / 1000.0; res.timePre = (timerProb0 + timerProb1) / 1000.0; return res; }
/** * Compute expected reachability rewards using value iteration. * * @param stpg The STPG * @param rewards The rewards * @param target Target states * @param inf States for which reward is infinite * @param min1 Min or max rewards for player 1 (true=min, false=max) * @param min2 Min or max rewards for player 2 (true=min, false=max) * @param init Optionally, an initial solution vector (will be overwritten) * @param known Optionally, a set of states for which the exact answer is known Note: if 'known' * is specified (i.e. is non-null, 'init' must also be given and is used for the exact values. */ protected ModelCheckerResult computeReachRewardsValIter( STPG stpg, STPGRewards rewards, BitSet target, BitSet inf, boolean min1, boolean min2, double init[], BitSet known) throws PrismException { ModelCheckerResult res; BitSet unknown; int i, n, iters; double soln[], soln2[], tmpsoln[]; boolean done; long timer; // Start value iteration timer = System.currentTimeMillis(); if (verbosity >= 1) mainLog.println( "Starting value iteration (" + (min1 ? "min" : "max") + (min2 ? "min" : "max") + ")..."); // Store num states n = stpg.getNumStates(); // Create solution vector(s) soln = new double[n]; soln2 = (init == null) ? new double[n] : init; // Initialise solution vectors. Use (where available) the following in order of preference: // (1) exact answer, if already known; (2) 0.0/infinity if in target/inf; (3) passed in initial // value; (4) 0.0 if (init != null) { if (known != null) { for (i = 0; i < n; i++) soln[i] = soln2[i] = known.get(i) ? init[i] : target.get(i) ? 0.0 : inf.get(i) ? Double.POSITIVE_INFINITY : init[i]; } else { for (i = 0; i < n; i++) soln[i] = soln2[i] = target.get(i) ? 0.0 : inf.get(i) ? Double.POSITIVE_INFINITY : init[i]; } } else { for (i = 0; i < n; i++) soln[i] = soln2[i] = target.get(i) ? 0.0 : inf.get(i) ? Double.POSITIVE_INFINITY : 0.0; } // Determine set of states actually need to compute values for unknown = new BitSet(); unknown.set(0, n); unknown.andNot(target); unknown.andNot(inf); if (known != null) unknown.andNot(known); // Start iterations iters = 0; done = false; while (!done && iters < maxIters) { // mainLog.println(soln); iters++; // Matrix-vector multiply and min/max ops stpg.mvMultRewMinMax(soln, rewards, min1, min2, soln2, unknown, false, null); // Check termination done = PrismUtils.doublesAreClose(soln, soln2, termCritParam, termCrit == TermCrit.ABSOLUTE); // Swap vectors for next iter tmpsoln = soln; soln = soln2; soln2 = tmpsoln; } // Finished value iteration timer = System.currentTimeMillis() - timer; if (verbosity >= 1) { mainLog.print("Value iteration (" + (min1 ? "min" : "max") + (min2 ? "min" : "max") + ")"); mainLog.println(" took " + iters + " iterations and " + timer / 1000.0 + " seconds."); } // Non-convergence is an error (usually) if (!done && errorOnNonConverge) { String msg = "Iterative method did not converge within " + iters + " iterations."; msg += "\nConsider using a different numerical method or increasing the maximum number of iterations"; throw new PrismException(msg); } // Return results res = new ModelCheckerResult(); res.soln = soln; res.numIters = iters; res.timeTaken = timer / 1000.0; return res; }