You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
9.2 KiB
281 lines
9.2 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2002-
|
|
// Authors:
|
|
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford, formerly University of Birmingham)
|
|
// * Joachim Klein <klein@tcs.inf.tu-dresden.de> (TU Dresden)
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// This file is part of PRISM.
|
|
//
|
|
// PRISM is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// PRISM is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with PRISM; if not, write to the Free Software Foundation,
|
|
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
//==============================================================================
|
|
|
|
// includes
|
|
#include "PrismMTBDD.h"
|
|
#include <cmath>
|
|
#include <util.h>
|
|
#include <cudd.h>
|
|
#include <dd.h>
|
|
#include <odd.h>
|
|
#include "PrismMTBDDGlob.h"
|
|
#include "jnipointer.h"
|
|
#include "prism.h"
|
|
#include "ExportIterations.h"
|
|
#include "IntervalIteration.h"
|
|
#include <memory>
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
JNIEXPORT jlong __jlongpointer JNICALL Java_mtbdd_PrismMTBDD_PM_1NondetUntilInterval
|
|
(
|
|
JNIEnv *env,
|
|
jclass cls,
|
|
jlong __jlongpointer t, // trans matrix
|
|
jlong __jlongpointer od, // odd
|
|
jlong __jlongpointer ndm, // nondeterminism mask
|
|
jlong __jlongpointer rv, // row vars
|
|
jint num_rvars,
|
|
jlong __jlongpointer cv, // col vars
|
|
jint num_cvars,
|
|
jlong __jlongpointer ndv, // nondet vars
|
|
jint num_ndvars,
|
|
jlong __jlongpointer y, // 'yes' states
|
|
jlong __jlongpointer m, // 'maybe' states
|
|
jboolean min, // min or max probabilities (true = min, false = max)
|
|
jint flags
|
|
)
|
|
{
|
|
// cast function parameters
|
|
DdNode *trans = jlong_to_DdNode(t); // trans matrix
|
|
ODDNode *odd = jlong_to_ODDNode(od); // odd
|
|
DdNode *mask = jlong_to_DdNode(ndm); // nondeterminism mask
|
|
DdNode **rvars = jlong_to_DdNode_array(rv); // row vars
|
|
DdNode **cvars = jlong_to_DdNode_array(cv); // col vars
|
|
DdNode **ndvars = jlong_to_DdNode_array(ndv); // nondet vars
|
|
DdNode *yes = jlong_to_DdNode(y); // 'yes' states
|
|
DdNode *maybe = jlong_to_DdNode(m); // 'maybe' states
|
|
|
|
// mtbdds
|
|
DdNode *a, *sol_above, *tmp_above, *sol_below, *tmp_below;
|
|
// timing stuff
|
|
long start1, start2, start3, stop;
|
|
double time_taken, time_for_setup, time_for_iters;
|
|
// misc
|
|
bool done;
|
|
int iters, i;
|
|
|
|
IntervalIteration helper(flags);
|
|
|
|
// start clocks
|
|
start1 = start2 = util_cpu_time();
|
|
|
|
// get a - filter out rows
|
|
PM_PrintToMainLog(env, "\nBuilding iteration matrix MTBDD... ");
|
|
Cudd_Ref(trans);
|
|
Cudd_Ref(maybe);
|
|
a = DD_Apply(ddman, APPLY_TIMES, trans, maybe);
|
|
i = DD_GetNumNodes(ddman, a);
|
|
PM_PrintToMainLog(env, "[nodes=%d] [%.1f Kb]\n", i, i*20.0/1024.0);
|
|
|
|
// initial solution
|
|
// (prob in 0 steps given by yes)
|
|
Cudd_Ref(yes);
|
|
sol_below = yes;
|
|
|
|
// initial solution from above: 1 for yes and maybe states
|
|
Cudd_Ref(yes);
|
|
Cudd_Ref(maybe);
|
|
sol_above = DD_Or(ddman, yes, maybe);
|
|
|
|
std::unique_ptr<ExportIterations> iterationExport;
|
|
if (PM_GetFlagExportIterations()) {
|
|
iterationExport.reset(new ExportIterations("PM_NondetUntilInterval"));
|
|
iterationExport->exportVector(sol_below, rvars, num_rvars, odd, 0);
|
|
iterationExport->exportVector(sol_above, rvars, num_rvars, odd, 1);
|
|
}
|
|
|
|
// get setup time
|
|
stop = util_cpu_time();
|
|
time_for_setup = (double)(stop - start2)/1000;
|
|
start2 = stop;
|
|
start3 = stop;
|
|
|
|
// start iterations
|
|
iters = 0;
|
|
done = false;
|
|
PM_PrintToMainLog(env, "\nStarting iterations (interval iteration)...\n");
|
|
|
|
bool below_unchanged = false, above_unchanged = false;
|
|
|
|
while (!done && iters < max_iters) {
|
|
below_unchanged = above_unchanged = false;
|
|
|
|
// if (iters%20==0) {
|
|
// PM_PrintToMainLog(env, "Iteration %d:\n", iters);
|
|
// DD_PrintTerminalsAndNumbers(ddman, sol, num_rvars);
|
|
// }
|
|
|
|
iters++;
|
|
|
|
// DD_PrintInfoBrief(ddman, sol, num_rvars);
|
|
|
|
// matrix-vector multiply (below)
|
|
Cudd_Ref(sol_below);
|
|
tmp_below = DD_PermuteVariables(ddman, sol_below, rvars, cvars, num_rvars);
|
|
Cudd_Ref(a);
|
|
tmp_below = DD_MatrixMultiply(ddman, a, tmp_below, cvars, num_cvars, MM_BOULDER);
|
|
|
|
// matrix-vector multiply (above)
|
|
Cudd_Ref(sol_above);
|
|
tmp_above = DD_PermuteVariables(ddman, sol_above, rvars, cvars, num_rvars);
|
|
Cudd_Ref(a);
|
|
tmp_above = DD_MatrixMultiply(ddman, a, tmp_above, cvars, num_cvars, MM_BOULDER);
|
|
|
|
// DD_PrintInfoBrief(ddman, tmp, num_rvars+num_ndvars);
|
|
|
|
// do min/max
|
|
if (min) {
|
|
// mask stuff
|
|
Cudd_Ref(mask);
|
|
tmp_below = DD_Apply(ddman, APPLY_MAX, tmp_below, mask);
|
|
// abstract
|
|
tmp_below = DD_MinAbstract(ddman, tmp_below, ndvars, num_ndvars);
|
|
|
|
// mask stuff
|
|
Cudd_Ref(mask);
|
|
tmp_above = DD_Apply(ddman, APPLY_MAX, tmp_above, mask);
|
|
// abstract
|
|
tmp_above = DD_MinAbstract(ddman, tmp_above, ndvars, num_ndvars);
|
|
}
|
|
else {
|
|
// abstract
|
|
tmp_below = DD_MaxAbstract(ddman, tmp_below, ndvars, num_ndvars);
|
|
// abstract
|
|
tmp_above = DD_MaxAbstract(ddman, tmp_above, ndvars, num_ndvars);
|
|
}
|
|
|
|
// put 1s (for 'yes' states) back into into solution vector
|
|
Cudd_Ref(yes);
|
|
tmp_below = DD_Apply(ddman, APPLY_MAX, tmp_below, yes);
|
|
Cudd_Ref(yes);
|
|
tmp_above = DD_Apply(ddman, APPLY_MAX, tmp_above, yes);
|
|
|
|
if (helper.flag_ensure_monotonic_from_below()) {
|
|
// below: do max of tmp_below with old solution
|
|
Cudd_Ref(sol_below);
|
|
tmp_below = DD_Apply(ddman, APPLY_MAX, tmp_below, sol_below);
|
|
}
|
|
if (helper.flag_ensure_monotonic_from_above()) {
|
|
// above: do min of tmp_below with old solution
|
|
Cudd_Ref(sol_above);
|
|
tmp_above = DD_Apply(ddman, APPLY_MIN, tmp_above, sol_above);
|
|
}
|
|
|
|
if (iterationExport) {
|
|
iterationExport->exportVector(tmp_below, rvars, num_rvars, odd, 0);
|
|
iterationExport->exportVector(tmp_above, rvars, num_rvars, odd, 1);
|
|
}
|
|
|
|
// check convergence
|
|
switch (term_crit) {
|
|
case TERM_CRIT_ABSOLUTE:
|
|
if (DD_EqualSupNorm(ddman, tmp_below, tmp_above, term_crit_param)) {
|
|
done = true;
|
|
}
|
|
break;
|
|
case TERM_CRIT_RELATIVE:
|
|
if (DD_EqualSupNormRel(ddman, tmp_below, tmp_above, term_crit_param)) {
|
|
done = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (sol_below == tmp_below) below_unchanged = true;
|
|
if (sol_above == tmp_above) above_unchanged = true;
|
|
|
|
if (!done && below_unchanged && above_unchanged) {
|
|
break;
|
|
}
|
|
|
|
// print occasional status update
|
|
if ((util_cpu_time() - start3) > UPDATE_DELAY) {
|
|
PM_PrintToMainLog(env, "Iteration %d: ", iters);
|
|
PM_PrintToMainLog(env, "sol_below=%d nodes sol_above=%d nodes", DD_GetNumNodes(ddman, sol_below), DD_GetNumNodes(ddman, sol_above));
|
|
// NB: but tmp was probably bigger than sol (pre min/max-abstract)
|
|
PM_PrintToMainLog(env, ", %.2f sec so far\n", ((double)(util_cpu_time() - start2)/1000));
|
|
start3 = util_cpu_time();
|
|
}
|
|
|
|
// prepare for next iteration
|
|
Cudd_RecursiveDeref(ddman, sol_below);
|
|
Cudd_RecursiveDeref(ddman, sol_above);
|
|
sol_below = tmp_below;
|
|
sol_above = tmp_above;
|
|
}
|
|
|
|
// stop clocks
|
|
stop = util_cpu_time();
|
|
time_for_iters = (double)(stop - start2)/1000;
|
|
time_taken = (double)(stop - start1)/1000;
|
|
|
|
// print iterations/timing info
|
|
PM_PrintToMainLog(env, "\nIterative method (interval iteration): %d iterations in %.2f seconds (average %.6f, setup %.2f)\n", iters, time_taken, time_for_iters/iters, time_for_setup);
|
|
|
|
DdNode *result;
|
|
if (helper.flag_select_midpoint() && done) { // we did converge, select midpoint
|
|
Cudd_Ref(sol_below);
|
|
Cudd_Ref(sol_above);
|
|
|
|
// compute midpoint for result
|
|
DdNode* difference = DD_Apply(ddman, APPLY_MINUS, sol_above, sol_below);
|
|
difference = DD_Apply(ddman, APPLY_DIVIDE, difference, DD_Constant(ddman, 2.0));
|
|
|
|
Cudd_Ref(sol_below);
|
|
result = DD_Apply(ddman, APPLY_PLUS, sol_below, difference);
|
|
// TODO: ensure that below <= result <= above?
|
|
|
|
// export midpoint as vector above and below
|
|
if (iterationExport) {
|
|
iterationExport->exportVector(result, rvars, num_rvars, odd, 0);
|
|
iterationExport->exportVector(result, rvars, num_rvars, odd, 1);
|
|
}
|
|
} else {
|
|
result = sol_below;
|
|
Cudd_Ref(result);
|
|
}
|
|
|
|
// free memory
|
|
Cudd_RecursiveDeref(ddman, a);
|
|
Cudd_RecursiveDeref(ddman, sol_below);
|
|
Cudd_RecursiveDeref(ddman, sol_above);
|
|
|
|
// if the iterative method didn't terminate, this is an error
|
|
if (!done) {
|
|
Cudd_RecursiveDeref(ddman, result);
|
|
if (below_unchanged && above_unchanged) {
|
|
PM_SetErrorMessage("In interval iteration, after %d iterations, both lower and upper iteration did not change anymore but don't have the required precision yet.\nThis could be caused by the MTBDD's engine collapsing of similar constants, consider setting a smaller value for -cuddepsilon or -cuddepsilon 0 to disable collapsing", iters);
|
|
} else {
|
|
PM_SetErrorMessage("Iterative method (interval iteration) did not converge within %d iterations.\nConsider using a different numerical method or increasing the maximum number of iterations", iters);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return ptr_to_jlong(result);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|