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.
1873 lines
58 KiB
1873 lines
58 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2002-
|
|
// Authors:
|
|
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford)
|
|
// * Hongyang Qu <hongyang.qu@comlab.ox.ac.uk> (University of Oxford)
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// 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 "PrismSparse.h"
|
|
#include <math.h>
|
|
#include <util.h>
|
|
#include <cudd.h>
|
|
#include <dd.h>
|
|
#include <odd.h>
|
|
#include <dv.h>
|
|
#include "sparse.h"
|
|
#include "PrismSparseGlob.h"
|
|
#include "jnipointer.h"
|
|
#include <new>
|
|
#include "eclipse.h"
|
|
|
|
typedef double REAL;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
JNIEXPORT jdouble __jlongpointer JNICALL Java_sparse_PrismSparse_PS_1NondetMultiReach
|
|
(
|
|
JNIEnv *env,
|
|
jclass cls,
|
|
jlong __jlongpointer t, // trans matrix
|
|
jlong __jlongpointer od, // odd
|
|
jlong __jlongpointer rv, // row vars
|
|
jint num_rvars,
|
|
jlong __jlongpointer cv, // col vars
|
|
jint num_cvars,
|
|
jlong __jlongpointer ndv, // nondet vars
|
|
jint num_ndvars,
|
|
jlongArray _targets, // target state sets
|
|
jintArray _relops, // target relops (0:=?, 1:>, 2:>=)
|
|
jdoubleArray _bounds, // target probability bounds
|
|
jlong __jlongpointer m, // 'maybe' states
|
|
jlong __jlongpointer _start, // initial state(s)
|
|
jint checkReach, // reachability analysis or LTL model checking
|
|
|
|
jlong __jlongpointer m_r, // 'maybe' states for the reward formula
|
|
jlong __jlongpointer trr // transition rewards
|
|
// Reward paramters for more complicated cases
|
|
//jlongArray _rewards, // sets of rewards for reward formulas
|
|
//jlongArray _targets_r, // target state sets for reward formulas
|
|
//jdoubleArray _bounds_r, // target probability bounds for reward formulas
|
|
//jlongArray _maybe_r, // maybe state sets for reward formulas
|
|
)
|
|
{
|
|
// cast function parameters
|
|
DdNode *trans = jlong_to_DdNode(t); // trans matrix
|
|
ODDNode *odd = jlong_to_ODDNode(od); // reachable states
|
|
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 *maybe = jlong_to_DdNode(m); // 'maybe' states
|
|
//DdNode *maybe_r = jlong_to_DdNode(m_r); // 'maybe' states for the reward formula
|
|
DdNode *start = jlong_to_DdNode(_start); // initial state(s)
|
|
DdNode *trans_rewards = NULL; // transition rewards
|
|
|
|
// target info
|
|
jlong *target_ptrs = NULL;
|
|
DdNode **targets = NULL;
|
|
jint *relops = NULL;
|
|
double *bounds = NULL;
|
|
// mtbdds
|
|
DdNode *a = NULL;
|
|
// model stats
|
|
int num_targets, n, nc, nc_r;
|
|
long nnz, nnz_r;
|
|
// sparse matrix
|
|
NDSparseMatrix *ndsm = NULL, *ndsm_r = NULL;
|
|
// vectors
|
|
double *yes1_vec = NULL, *yes2_vec = NULL, *maybe_vec = NULL/*, *maybe_vec_r = NULL*/;
|
|
// timing stuff
|
|
long start1, start2, start3, stop, stop2;
|
|
double time_taken, time_for_setup, time_for_lp;
|
|
// lp stuff
|
|
REAL *arr_reals = NULL;// *lp_soln = NULL;
|
|
int *arr_ints = NULL;
|
|
bool selfloop;
|
|
int arr_size, count, res;
|
|
// misc
|
|
int i, j, k, k_r, l1, h1, l2, h2, l2_r, h2_r, start_index;
|
|
double d1, d2, kb, kbt;
|
|
bool done, first;
|
|
jclass vn_cls;
|
|
jmethodID vn_mid;
|
|
int n_maybe_r = 0; // the number of maybe states for rewards
|
|
|
|
double lp_result = 0.0;
|
|
|
|
/********************** Multiple rewards ****************************
|
|
// Variables for rewards
|
|
jlong *rewards_ptrs = env->GetLongArrayElements(_rewards, 0);;
|
|
DdNode **rewards; // transition rewards
|
|
int num_rewards = (int)env->GetArrayLength(_rewards);
|
|
rewards = new DdNode*[num_rewards];
|
|
for (i = 0; i < num_rewards; i++)
|
|
rewards[i] = jlong_to_DdNode(rewards_ptrs[i]);
|
|
|
|
// Variables for reward formulas
|
|
jlong *targets_r_ptrs = env->GetLongArrayElements(_targets_r, 0);;
|
|
DdNode **targets_r; // target sets for reward formulas
|
|
int num_targets_r = (int)env->GetArrayLength(_targets_r);
|
|
targets_r = new DdNode*[num_targets_r];
|
|
double *bounds_r = env->GetDoubleArrayElements(_bounds_r, 0);
|
|
for (i = 0; i < num_targets_r; i++)
|
|
targets_r[i] = jlong_to_DdNode(targets_r_ptrs[i]);
|
|
DdNode* yes_r[num_targets_r];
|
|
double* yes_vecs_r[num_targets_r];
|
|
for(i=0; i<num_targets_r; i++)
|
|
yes_r[i] = targets_r[i];
|
|
********************************************************************/
|
|
|
|
// extract arrays of target info from function parameters
|
|
num_targets = (int)env->GetArrayLength(_targets);
|
|
target_ptrs = env->GetLongArrayElements(_targets, 0);
|
|
targets = new DdNode*[num_targets];
|
|
for (i = 0; i < num_targets; i++) targets[i] = jlong_to_DdNode(target_ptrs[i]);
|
|
relops = env->GetIntArrayElements(_relops, 0);
|
|
bounds = env->GetDoubleArrayElements(_bounds, 0);
|
|
|
|
// Display some target info (just a test)
|
|
PS_PrintToMainLog(env, "\n%d Targets:\n", num_targets);
|
|
for (i = 0; i < num_targets; i++) {
|
|
PS_PrintToMainLog(env, "#%d: ", i);
|
|
switch (relops[i]) {
|
|
case 0: PS_PrintToMainLog(env, "Pmax=?"); break;
|
|
case 1: PS_PrintToMainLog(env, ">%g", bounds[i]); break;
|
|
case 2: PS_PrintToMainLog(env, ">=%g", bounds[i]); break;
|
|
case 3: PS_PrintToMainLog(env, "Rmax=?"); break;
|
|
case 4: PS_PrintToMainLog(env, ">=%g", bounds[i]); break;
|
|
}
|
|
PS_PrintToMainLog(env, " (%.0f states)\n", DD_GetNumMinterms(ddman, targets[i], num_rvars));
|
|
}
|
|
|
|
//DdNode *yes1 = targets[0];
|
|
//DdNode *yes2 = targets[1];
|
|
DdNode* yes[num_targets];
|
|
double* yes_vecs[num_targets];
|
|
for(i=0; i<num_targets; i++)
|
|
yes[i] = targets[i];
|
|
|
|
// exception handling around whole function
|
|
try {
|
|
|
|
// start clocks
|
|
start1 = start2 = util_cpu_time();
|
|
|
|
// get a - filter out rows
|
|
Cudd_Ref(trans);
|
|
Cudd_Ref(maybe);
|
|
if(checkReach) // For reachability, we only use maybe
|
|
a = DD_Apply(ddman, APPLY_TIMES, trans, maybe);
|
|
else { // For LTL formulas, we need both maybe and yes
|
|
DdNode *maybe_yes = maybe;
|
|
for(i=0; i<num_targets; i++) {
|
|
Cudd_Ref(yes[i]);
|
|
maybe_yes = DD_Or(ddman, maybe_yes, yes[i]);
|
|
}
|
|
a = DD_Apply(ddman, APPLY_TIMES, trans, maybe_yes);
|
|
}
|
|
|
|
// get number of states
|
|
n = odd->eoff + odd->toff;
|
|
|
|
// build sparse matrix
|
|
PS_PrintToMainLog(env, "\nBuilding sparse matrix... ");
|
|
ndsm = build_nd_sparse_matrix(ddman, a, rvars, cvars, num_rvars, ndvars, num_ndvars, odd);
|
|
// get number of transitions/choices
|
|
nnz = ndsm->nnz;
|
|
nc = ndsm->nc;
|
|
kb = ndsm->mem;
|
|
kbt = kb;
|
|
// print out info
|
|
PS_PrintToMainLog(env, "[n=%d, nc=%d, nnz=%d, k=%d] ", n, nc, nnz, ndsm->k);
|
|
PS_PrintMemoryToMainLog(env, "[", kb, "]\n");
|
|
|
|
// get vectors for yes/maybe
|
|
PS_PrintToMainLog(env, "Creating vectors for yes... ");
|
|
for(i=0; i<num_targets; i++) {
|
|
yes_vecs[i] = mtbdd_to_double_vector(ddman, yes[i], rvars, num_rvars, odd);
|
|
kb = n*8.0/1024.0;
|
|
kbt += kb;
|
|
PS_PrintMemoryToMainLog(env, "[", kb, "]\n");
|
|
}
|
|
/*PS_PrintToMainLog(env, "Creating vectors for yes2... ");
|
|
yes2_vec = mtbdd_to_double_vector(ddman, yes2, rvars, num_rvars, odd);
|
|
kb = n*8.0/1024.0;
|
|
kbt += kb;
|
|
PS_PrintMemoryToMainLog(env, "[", kb, "]\n");*/
|
|
PS_PrintToMainLog(env, "Creating vector for maybe... ");
|
|
maybe_vec = mtbdd_to_double_vector(ddman, maybe, rvars, num_rvars, odd);
|
|
kb = n*8.0/1024.0;
|
|
kbt += kb;
|
|
PS_PrintMemoryToMainLog(env, "[", kb, "]\n");
|
|
|
|
// get index of single (first) initial state
|
|
start_index = get_index_of_first_from_bdd(ddman, start, rvars, num_rvars, odd);
|
|
PS_PrintToMainLog(env, "Initial state index: %1d\n", start_index);
|
|
|
|
// print total memory usage
|
|
PS_PrintMemoryToMainLog(env, "TOTAL: [", kbt, "]\n");
|
|
|
|
// store local copies of sparse matrix stuff
|
|
double *non_zeros = ndsm->non_zeros;
|
|
unsigned char *row_counts = ndsm->row_counts;
|
|
int *row_starts = (int *)ndsm->row_counts;
|
|
unsigned char *choice_counts = ndsm->choice_counts;
|
|
int *choice_starts = (int *)ndsm->choice_counts;
|
|
bool use_counts = ndsm->use_counts;
|
|
unsigned int *cols = ndsm->cols;
|
|
|
|
/***************** set up rewards *******************/
|
|
/*double *non_zeros_r;
|
|
unsigned char *choice_counts_r;
|
|
int *choice_starts_r;
|
|
bool use_counts_r;
|
|
unsigned int *cols_r;
|
|
|
|
if(relops[0] > 2) {
|
|
trans_rewards = jlong_to_DdNode(trr); // transition rewards
|
|
Cudd_Ref(trans_rewards);
|
|
trans_rewards = DD_Apply(ddman, APPLY_TIMES, trans_rewards, maybe);
|
|
PS_PrintToMainLog(env, "Building sparse matrix (transition rewards)... ");
|
|
ndsm_r = build_sub_nd_sparse_matrix(ddman, a, trans_rewards, rvars, cvars, num_rvars, ndvars, num_ndvars, odd);
|
|
nnz_r = ndsm_r->nnz;
|
|
nc_r = ndsm_r->nc;
|
|
// print out info
|
|
PS_PrintToMainLog(env, "[n=%d, nc=%d, nnz=%d, k=%d] ", n, nc_r, nnz_r, ndsm_r->k);
|
|
kb = (nnz_r*12.0+nc_r*4.0+n*4.0)/1024.0;
|
|
kbt += kb;
|
|
PS_PrintMemoryToMainLog(env, "[", kb, "]\n");
|
|
non_zeros_r = ndsm_r->non_zeros;
|
|
choice_counts_r = ndsm_r->choice_counts;
|
|
choice_starts_r = (int *)ndsm_r->choice_counts;
|
|
use_counts_r = ndsm_r->use_counts;
|
|
cols_r = ndsm_r->cols;
|
|
//for(i=0; i<nnz_r; i++)
|
|
// printf("non_zeros_r[%1d] = %g\n", i, non_zeros_r[i]);
|
|
/ *PS_PrintToMainLog(env, "Creating vector for reward maybe... ");
|
|
maybe_vec_r = mtbdd_to_double_vector(ddman, maybe_r, rvars, num_rvars, odd);
|
|
for(i=0; i<n; i++)
|
|
if(maybe_vec_r[i] > 0)
|
|
n_maybe_r ++;
|
|
kb = n*8.0/1024.0;
|
|
kbt += kb;
|
|
PS_PrintMemoryToMainLog(env, "[", kb, "]\n"); * /
|
|
//maybe_vec_r = maybe_vec;
|
|
}*/
|
|
/***************** end of set up *******************/
|
|
|
|
// Set up LP problem
|
|
PS_PrintToMainLog(env, "\nBuilding LP problem...\n");
|
|
// Compute number of vars/constraints
|
|
int maybe_nc = 0;
|
|
for (i = 0; i < n; i++) {
|
|
if (maybe_vec[i]> 0) {
|
|
h1 = use_counts ? row_counts[i] : (row_starts[i+1] - row_starts[i]);
|
|
maybe_nc += h1;
|
|
}
|
|
}
|
|
int num_yes12 = 0;
|
|
int num_maybe = 0;
|
|
for (i = 0; i < n; i++) {
|
|
//if (yes1_vec[i] > 0 || yes2_vec[i] > 0) num_yes12++;
|
|
for(j=0; j<num_targets; j++)
|
|
if(yes_vecs[j][i]> 0) {
|
|
num_yes12++;
|
|
break;
|
|
}
|
|
if (maybe_vec[i]> 0 ) num_maybe++;
|
|
}
|
|
int num_lp_vars = maybe_nc + num_yes12;
|
|
//printf("num_lp_vars = %d + %d = %d\n", maybe_nc, num_yes12, num_lp_vars);
|
|
//int num_constr = num_maybe + num_yes12;
|
|
//printf("num_constr = %d + %d = %d\n", num_maybe, num_yes12, num_constr);
|
|
|
|
/*yes1_vec = yes_vecs[0];
|
|
yes2_vec = yes_vecs[1];
|
|
|
|
start3 = util_cpu_time();
|
|
|
|
if ((lp=make_lp(n, 0)) == NULL) throw "Could not create LP problem";
|
|
// Lower verbosity: Warnings and errors only
|
|
//set_verbose(lp, IMPORTANT);
|
|
|
|
// Compute array size: max num elements in a row + 1
|
|
// or number of elements in maybe, which ever is greater
|
|
arr_size = 0;
|
|
h1 = h2 = 0;
|
|
for (i = 0; i < n; i++) {
|
|
if (!use_counts) { l1 = row_starts[i]; h1 = row_starts[i+1]; }
|
|
else { l1 = h1; h1 += row_counts[i]; }
|
|
for (j = l1; j < h1; j++) {
|
|
h2 = use_counts ? choice_counts[j] : (choice_starts[j+1] - choice_starts[j]);
|
|
if (h2 > arr_size) arr_size = h2;
|
|
}
|
|
}
|
|
arr_size++;
|
|
count = 0;
|
|
for (i = 0; i < n; i++) if (maybe_vec[i] > 0) count++;
|
|
if (count > arr_size) arr_size = count;
|
|
// Allocate vectors for use in building LP problem
|
|
arr_reals = new REAL[arr_size];
|
|
arr_ints = new int[arr_size];
|
|
|
|
// Set objective function for LP problem
|
|
set_maxim(lp);
|
|
count = 0;
|
|
/ * for (i = 0; i < n; i++) if (maybe_vec[i] > 0) {
|
|
arr_reals[count] = 1.0;
|
|
arr_ints[count] = i+1;
|
|
count++;
|
|
}
|
|
set_obj_fnex(lp, count, arr_reals, arr_ints);* /
|
|
|
|
// Add columns to LP problem
|
|
h1 = h2 = 0;
|
|
for (i = 0; i < n; i++) {
|
|
printf("%d: %s%s%s\n", i, maybe_vec[i]>0?"1":"0", yes1_vec[i]>0?"1":"0", yes2_vec[i]>0?"1":"0");
|
|
if (yes1_vec[i] > 0 || yes2_vec[i] > 0) {
|
|
printf("yes %d\n", i);
|
|
arr_ints[0] = i+1;
|
|
arr_reals[0] = 1;
|
|
count = 1;
|
|
if (yes2_vec[i] > 0) {
|
|
|
|
count++;
|
|
}
|
|
add_columnex(lp, 1, arr_reals, arr_ints);
|
|
}
|
|
if (!use_counts) { l1 = row_starts[i]; h1 = row_starts[i+1]; }
|
|
else { l1 = h1; h1 += row_counts[i]; }
|
|
for (j = l1; j < h1; j++) {
|
|
if (!use_counts) { l2 = choice_starts[j]; h2 = choice_starts[j+1]; }
|
|
else { l2 = h2; h2 += choice_counts[j]; }
|
|
if (maybe_vec[i] > 0) {
|
|
arr_ints[0] = i+1;
|
|
arr_reals[0] = 1.0;
|
|
count = 1;
|
|
d2 = 0.0;
|
|
for (k = l2; k < h2; k++) {
|
|
printf("#%d (%d.%d): %d,%f\n", count, i, j, cols[k], non_zeros[k]);
|
|
// Ignore no cols
|
|
printf("%s%s%s\n", maybe_vec[cols[k]]>0?"1":"0", yes1_vec[cols[k]]>0?"1":"0", yes2_vec[cols[k]]>0?"1":"0");
|
|
if (maybe_vec[cols[k]] == 0 && yes1_vec[cols[k]] == 0 && yes2_vec[cols[k]] == 0) continue;
|
|
// Normal case
|
|
if (1) {
|
|
arr_ints[count] = cols[k]+1;
|
|
arr_reals[count] = -non_zeros[k];
|
|
count++;
|
|
}
|
|
}
|
|
for (k = 0; k < count; k++) printf(" %f", arr_reals[k]); printf("\n");
|
|
for (k = 0; k < count; k++) printf(" %d", arr_ints[k]); printf("\n");
|
|
add_columnex(lp, count, arr_reals, arr_ints);
|
|
}
|
|
}
|
|
}
|
|
|
|
print_lp(lp);
|
|
|
|
// get setup time
|
|
stop = util_cpu_time();
|
|
time_for_setup = (double)(stop - start3)/1000;
|
|
start2 = stop;
|
|
|
|
// Solve LP problem
|
|
PS_PrintToMainLog(env, "Solving LP problem...\n");
|
|
res = solve(lp);
|
|
|
|
//Get LP solving time
|
|
stop2 = util_cpu_time();
|
|
time_for_lp = (double)(stop2 - start2)/1000;
|
|
|
|
if (res != 0) throw "Could not solve LP problem";
|
|
get_ptr_variables(lp, &lp_soln);
|
|
//print_solution(lp, 2);
|
|
|
|
// Reuse yes vector to store/return soln
|
|
for (i = 0; i < n; i++) {
|
|
//if (yes2_vec[i] == 0.0) yes2_vec[i] = lp_soln[i];
|
|
}
|
|
|
|
// stop clocks
|
|
stop = util_cpu_time();
|
|
time_for_lp = (double)(stop - start2)/1000;
|
|
time_taken = (double)(stop - start3)/1000;
|
|
|
|
// print timing info
|
|
PS_PrintToMainLog(env, "\nLP problem solved in %.2f seconds (setup %.2f, lpsolve %.2f)\n", time_taken, time_for_setup, time_for_lp);*/
|
|
|
|
/*
|
|
* Hongyang: Use Eclipse with COIN CBC solver
|
|
*/
|
|
FILE *f; /* FILE pointer */
|
|
|
|
// Generate LP for the objectives
|
|
start3 = util_cpu_time();
|
|
|
|
ec_refs Vars;
|
|
ec_ref Cost;
|
|
pword varlist;
|
|
//int yes_vec[n];
|
|
//int map_var[n+1];
|
|
int *yes_vec;
|
|
int *map_var;
|
|
|
|
yes_vec = new int[n];
|
|
map_var = new int[n+1];
|
|
|
|
arr_ints = new int[n];
|
|
int sp;
|
|
|
|
int yes_nc = 0; // the total number of choices of all target states
|
|
/*int *map_var_r;
|
|
|
|
if(relops[0] > 2) {
|
|
map_var_r = new int[n];
|
|
k = 0;
|
|
for(i=0; i<n; i++)
|
|
if(maybe_vec_r[i] > 0)
|
|
map_var_r[i] = k++;
|
|
else
|
|
map_var_r[i] = -1;
|
|
}*/
|
|
|
|
if(checkReach) {
|
|
PS_PrintToMainLog(env, "Check reachability...\n");
|
|
// Maps states to ECLiPSe variables.
|
|
// Each yes state has a coresponding variable.
|
|
// Each maybe state has one or more variables.
|
|
|
|
// merge all yes vectors into one
|
|
int flag = 0;
|
|
for(i=0; i<n; i++) {
|
|
flag = 0;
|
|
for(j=0; j<num_targets; j++)
|
|
if(yes_vecs[j][i]> 0) {
|
|
yes_vec[i] = 1;
|
|
flag = 1;
|
|
break;
|
|
}
|
|
if(!flag)
|
|
yes_vec[i] = 0;
|
|
}
|
|
|
|
//if (arr_reals) delete[] arr_reals;
|
|
PS_PrintToMainLog(env, "Number of LP variables = %1d\n", num_lp_vars + n_maybe_r);
|
|
arr_reals = new REAL[num_lp_vars + n_maybe_r];
|
|
|
|
// create map vector
|
|
count = 0;
|
|
for(i=0; i<n; i++) {
|
|
if(yes_vec[i]> 0)
|
|
map_var[i] = count++;
|
|
else {
|
|
if(maybe_vec[i]> 0) {
|
|
map_var[i] = count;
|
|
count += use_counts ? row_counts[i] : (row_starts[i+1] - row_starts[i]);
|
|
} else
|
|
map_var[i] = count;
|
|
}
|
|
}
|
|
map_var[n] = num_lp_vars;
|
|
|
|
/*printf("map_var = ");
|
|
for(i=0; i<=n; i++)
|
|
printf(" %1d", map_var[i]);
|
|
printf("\n");
|
|
fflush(stdout);*/
|
|
|
|
// Initialize ECLiPSe
|
|
ec_init();
|
|
|
|
// Load Eplex library
|
|
ec_post_string("lib(eplex)");
|
|
|
|
// Create ECLiPSe variables
|
|
Vars = ec_refs_create_newvars(num_lp_vars + n_maybe_r);
|
|
Cost = ec_ref_create_newvar();
|
|
varlist = ec_listofrefs(Vars);
|
|
|
|
// Define the domain of the variables
|
|
ec_post_goal(ec_term(
|
|
ec_did("::",2),
|
|
varlist,
|
|
ec_term(ec_did("..",2), ec_double(0.0), ec_double(1e20))));
|
|
|
|
stop = util_cpu_time();
|
|
time_for_setup = (double)(stop - start3)/1000;
|
|
start2 = stop;
|
|
|
|
// Add constraints to LP problem
|
|
int x;
|
|
l1 = h1 = 0;
|
|
for (i = 0; i < n; i++) {
|
|
// Add constraints for maybe states
|
|
if (maybe_vec[i]> 0) {
|
|
for(k=0; k<num_lp_vars; k++)
|
|
arr_reals[k] = 0.0;
|
|
|
|
if (!use_counts) {
|
|
l1 = row_starts[i];
|
|
h1 = row_starts[i+1];
|
|
} else {
|
|
l1 = h1;
|
|
h1 += row_counts[i];
|
|
}
|
|
for (j = l1; j < h1; j++) // \Sigma_{v\in V/F} y_{(v, \gamma)}
|
|
arr_reals[map_var[i]+j-l1] = 1.0;
|
|
|
|
count = h1-l1;
|
|
int l3, h3;
|
|
h3 = h2 = 0;
|
|
for (x = 0; x < n; x++) { // h2: row index
|
|
if(maybe_vec[x]> 0) {
|
|
if (!use_counts) {
|
|
l3 = row_starts[x];
|
|
h3 = row_starts[x+1];
|
|
} else { // Attention: there could exist a bug here!!!!!!!
|
|
l3 = h3;
|
|
h3 += row_counts[x];
|
|
}
|
|
for (j = l3; j < h3; j++) { // j: choice index; x+j: variable index
|
|
if (!use_counts) {
|
|
l2 = choice_starts[j];
|
|
h2 = choice_starts[j+1];
|
|
} else {
|
|
l2 = h2;
|
|
h2 += choice_counts[j];
|
|
}
|
|
for(k=l2; k<h2; k++) { // k: column index
|
|
if(cols[k] == i) {
|
|
// get the index of the corresponding variable
|
|
double old_value = arr_reals[map_var[x]+j-l3];
|
|
arr_reals[map_var[x]+j-l3] -= non_zeros[k];
|
|
//printf("map_var[%1d]+%1d-%1d = %1d\n", x, j, l3, map_var[x]+j-l3);
|
|
if(old_value == 0.0 && arr_reals[map_var[x]+j-l3] != 0.0)
|
|
count++;
|
|
else if(old_value != 0.0 && arr_reals[map_var[x]+j-l3] == 0.0)
|
|
count--;
|
|
}
|
|
}
|
|
}
|
|
} else if(use_counts) {
|
|
l3 = h3;
|
|
h3 += row_counts[x];
|
|
for (j = l3; j < h3; j++)
|
|
h2 += choice_counts[j];
|
|
}
|
|
}
|
|
|
|
/*printf(" arr_reals:");
|
|
for (k = 0; k < num_lp_vars; k++)
|
|
printf(" %1.1f", arr_reals[k]);
|
|
printf(" = %1.1f", (start_index==i ? 1.0 : 0.0));
|
|
printf(" count = %1d\n", count);
|
|
fflush(stdout);*/
|
|
|
|
pword tail = ec_nil();
|
|
x = 0;
|
|
|
|
for(k=num_lp_vars-1; k>=0; k--)
|
|
if(arr_reals[k] != 0.0)
|
|
tail = ec_list(ec_refs_get(Vars, k), tail);
|
|
for(k=0; k<num_lp_vars; k++)
|
|
if(arr_reals[k] != 0.0)
|
|
arr_reals[x++] = arr_reals[k];
|
|
ec_post_goal(ec_term(ec_did(("$="),2),
|
|
ec_term(ec_did("*",2),
|
|
tail,
|
|
ec_listofdouble(count, arr_reals)),
|
|
ec_double((start_index==i ? 1.0 : 0.0))));
|
|
/*ec_post_goal(ec_term(ec_did(("$="),2),
|
|
ec_term(ec_did("*",2),
|
|
varlist,
|
|
ec_listofdouble(num_lp_vars, arr_reals)),
|
|
ec_double((start_index==i ? 1.0 : 0.0))));*/
|
|
} else if(use_counts) {
|
|
l1 = h1;
|
|
h1 += row_counts[i];
|
|
}
|
|
}
|
|
for (i = 0; i < n; i++) {
|
|
if(yes_vec[i]> 0) {
|
|
for(k=0; k<num_lp_vars; k++)
|
|
arr_reals[k] = 0.0;
|
|
|
|
count = 1;
|
|
h1 = h2 = 0;
|
|
for (x = 0; x < n; x++) { // x: row index
|
|
if(maybe_vec[x]> 0) {
|
|
if (!use_counts) {
|
|
l1 = row_starts[x];
|
|
h1 = row_starts[x+1];
|
|
} else {
|
|
l1 = h1;
|
|
h1 += row_counts[x];
|
|
}
|
|
if(x == i) {
|
|
if(use_counts)
|
|
for (j = l1; j < h1; j++)
|
|
h2 += choice_counts[j];
|
|
continue;
|
|
}
|
|
for (j = l1; j < h1; j++) { // j: choice index; x+j: variable index
|
|
if (!use_counts) {
|
|
l2 = choice_starts[j];
|
|
h2 = choice_starts[j+1];
|
|
} else {
|
|
l2 = h2;
|
|
h2 += choice_counts[j];
|
|
}
|
|
for(k=l2; k<h2; k++) { // k: column index
|
|
if(cols[k] == i) {
|
|
// get the index of the corresponding variable
|
|
arr_reals[map_var[x]+j-l1] = -non_zeros[k];
|
|
//printf("map_var[%1d]+%1d-%1d = %1d\n", x, j, l1, map_var[x]+j-l1);
|
|
//printf("arr_reals[%1d] = %1.1f\n", map_var[x]+j-l1, -non_zeros[k]);
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
} else if(use_counts) {
|
|
l1 = h1;
|
|
h1 += row_counts[x];
|
|
for (j = l1; j < h1; j++)
|
|
h2 += choice_counts[j];
|
|
}
|
|
}
|
|
|
|
arr_reals[map_var[i]] = 1.0;
|
|
/*printf(" arr_reals:");
|
|
for (k = 0; k < num_lp_vars; k++)
|
|
printf(" %1.1f", arr_reals[k]);
|
|
printf(" = 0.0");
|
|
printf(" count = %1d\n", count);
|
|
fflush(stdout);*/
|
|
|
|
pword tail = ec_nil();
|
|
x = 0;
|
|
|
|
for(k=num_lp_vars-1; k>=0; k--)
|
|
if(arr_reals[k] != 0.0)
|
|
tail = ec_list(ec_refs_get(Vars, k), tail);
|
|
for(k=0; k<num_lp_vars; k++)
|
|
if(arr_reals[k] != 0.0)
|
|
arr_reals[x++] = arr_reals[k];
|
|
ec_post_goal(ec_term(ec_did(("$="),2),
|
|
ec_term(ec_did("*",2),
|
|
tail,
|
|
ec_listofdouble(count, arr_reals)),
|
|
ec_double(0.0)));
|
|
|
|
/*ec_post_goal(ec_term(ec_did(("$="),2),
|
|
ec_term(ec_did("*",2),
|
|
varlist,
|
|
ec_listofdouble(num_lp_vars, arr_reals)),
|
|
ec_double(0.0)));*/
|
|
}
|
|
}
|
|
|
|
PS_PrintToMainLog(env, "Adding extra constraints for probabilisitic bounds\n");
|
|
for(i=0; i<num_targets; i++) {
|
|
pword tail = ec_nil();
|
|
for(k=n-1; k>=0; k--)
|
|
if(yes_vecs[i][k]> 0)
|
|
tail = ec_list(ec_refs_get(Vars, map_var[k]), tail);
|
|
x=0;
|
|
for(k=0; k<n; k++)
|
|
if(yes_vecs[i][k]> 0)
|
|
arr_reals[x++] = 1.0;
|
|
ec_post_goal(ec_term(ec_did("$>=",2),
|
|
ec_term(ec_did("*",2),
|
|
tail,
|
|
ec_listofdouble(x, arr_reals)),
|
|
ec_double(bounds[i])));
|
|
}
|
|
|
|
PS_PrintToMainLog(env, "Computing optimisation...\n");
|
|
fflush(stdout);
|
|
pword tail = ec_nil();
|
|
x = 0;
|
|
|
|
if(relops[0]> 0 && relops[0] <= 2) {
|
|
for(k=n-1; k>=0; k--)
|
|
if(yes_vec[k]> 0)
|
|
tail = ec_list(ec_refs_get(Vars, map_var[k]), tail);
|
|
for(k=0; k<n; k++)
|
|
if(yes_vec[k]> 0)
|
|
arr_reals[x++] = 1.0;
|
|
} else if(relops[0] == 0) {
|
|
for(k=n-1; k>=0; k--)
|
|
if(yes_vecs[0][k]> 0)
|
|
tail = ec_list(ec_refs_get(Vars, map_var[k]), tail);
|
|
for(k=0; k<n; k++)
|
|
if(yes_vecs[0][k]> 0)
|
|
arr_reals[x++] = 1.0;
|
|
} else {
|
|
/*x = 1;
|
|
arr_reals[0] = 1.0;
|
|
tail = ec_list(ec_refs_get(Vars, map_var_r[start_index]+num_lp_vars), tail);*/
|
|
PS_PrintToMainLog(env, "computing max function for rewards ...\n");
|
|
double *non_zeros_r;
|
|
unsigned char *choice_counts_r;
|
|
int *choice_starts_r;
|
|
bool use_counts_r;
|
|
unsigned int *cols_r;
|
|
trans_rewards = jlong_to_DdNode(trr); // transition rewards
|
|
Cudd_Ref(trans_rewards);
|
|
trans_rewards = DD_Apply(ddman, APPLY_TIMES, trans_rewards, maybe);
|
|
PS_PrintToMainLog(env, "Building sparse matrix (transition rewards)... ");
|
|
ndsm_r = build_sub_nd_sparse_matrix(ddman, a, trans_rewards, rvars, cvars, num_rvars, ndvars, num_ndvars, odd);
|
|
nnz_r = ndsm_r->nnz;
|
|
nc_r = ndsm_r->nc;
|
|
// print out info
|
|
PS_PrintToMainLog(env, "[n=%d, nc=%d, nnz=%d, k=%d] ", n, nc_r, nnz_r, ndsm_r->k);
|
|
kb = (nnz_r*12.0+nc_r*4.0+n*4.0)/1024.0;
|
|
kbt += kb;
|
|
PS_PrintMemoryToMainLog(env, "[", kb, "]\n");
|
|
non_zeros_r = ndsm_r->non_zeros;
|
|
choice_counts_r = ndsm_r->choice_counts;
|
|
choice_starts_r = (int *)ndsm_r->choice_counts;
|
|
use_counts_r = ndsm_r->use_counts;
|
|
cols_r = ndsm_r->cols;
|
|
|
|
for(i=0; i<num_lp_vars; i++)
|
|
arr_reals[i] = 0;
|
|
|
|
h1 = h2 = 0;
|
|
for(i=0; i<n; i++)
|
|
if(maybe_vec[i]> 0) {
|
|
if (!use_counts) { // assume we always do not use counts
|
|
l1 = row_starts[i];
|
|
h1 = row_starts[i+1];
|
|
} else { // Problematic
|
|
l1 = h1;
|
|
h1 += row_counts[i];
|
|
}
|
|
for (j = l1; j < h1; j++) {// \Sigma_{v\in V/F} y_{(v, \gamma)}*c_{(v, \gamma)}
|
|
if (!use_counts) {
|
|
l2 = choice_starts[j];
|
|
h2 = choice_starts[j+1];
|
|
} else {
|
|
l2 = h2;
|
|
h2 += choice_counts[j];
|
|
}
|
|
if (!use_counts_r) {
|
|
l2_r = choice_starts_r[j];
|
|
h2_r = choice_starts_r[j+1];
|
|
} else {
|
|
l2_r = h2_r;
|
|
h2_r += choice_counts_r[j];
|
|
}
|
|
k_r = l2_r;
|
|
while (k_r < h2_r && cols_r[k_r] != cols[l2])
|
|
k_r++;
|
|
// if there is one, add reward * prob to reward value
|
|
if (k_r < h2_r) {
|
|
arr_reals[map_var[i]+j-l1] = non_zeros_r[k_r];
|
|
}
|
|
}
|
|
} else if(use_counts) { // count the number of choices for non maybe nodes. Is it necessary?
|
|
l1 = h1;
|
|
h1 += row_counts[i];
|
|
for (j = l1; j < h1; j++) {
|
|
h2 += choice_counts[j];
|
|
h2_r += choice_counts_r[j];
|
|
}
|
|
}
|
|
/*PS_PrintToMainLog(env, " arr_reals:");
|
|
for (k = 0; k < num_lp_vars; k++)
|
|
PS_PrintToMainLog(env, " %1.1f", arr_reals[k]);
|
|
fflush(stdout);*/
|
|
|
|
for(k=num_lp_vars-1; k>=0; k--)
|
|
if(arr_reals[k] != 0.0)
|
|
tail = ec_list(ec_refs_get(Vars, k), tail);
|
|
for(k=0; k<num_lp_vars; k++)
|
|
if(arr_reals[k] != 0.0)
|
|
arr_reals[x++] = arr_reals[k];
|
|
|
|
}
|
|
|
|
ec_post_goal( ec_term(ec_did("optimize", 2),
|
|
ec_term(ec_did("max", 1),
|
|
ec_term(ec_did("*",2), tail, ec_listofdouble(x, arr_reals))),
|
|
ec_ref_get(Cost)));
|
|
/*ec_post_goal( ec_term(ec_did("optimize", 2),
|
|
ec_term(ec_did("max", 1),
|
|
ec_term(ec_did("*",2), varlist, ec_listofdouble(num_lp_vars, pc))),
|
|
ec_ref_get(Cost)));*/
|
|
} else { // ------------------------------ LTL model checking ----------------------------
|
|
PS_PrintToMainLog(env, "Check LTL formulas...\n");
|
|
|
|
int num_map;
|
|
int yes_count = 0; // the number of target states
|
|
|
|
// Compute the number of lp variables for LTL model checking
|
|
maybe_nc = 0; // number of variables for maybe states
|
|
h1 = h2 = 0;
|
|
count = 0;
|
|
for (i = 0; i < n; i++) {
|
|
if (!use_counts) {
|
|
l1 = row_starts[i];
|
|
h1 = row_starts[i+1];
|
|
} else {
|
|
l1 = h1;
|
|
h1 += row_counts[i];
|
|
}
|
|
k=0;
|
|
for (j = l1; j < h1; j++) { // j: choice index; x+j: variable index
|
|
if (!use_counts) {
|
|
l2 = choice_starts[j];
|
|
h2 = choice_starts[j+1];
|
|
} else {
|
|
l2 = h2;
|
|
h2 += choice_counts[j];
|
|
}
|
|
if(h2-l2>1 || cols[l2] != i || non_zeros[l2]!=1.0)
|
|
k++;
|
|
}
|
|
if (maybe_vec[i]> 0) {
|
|
maybe_nc += k;
|
|
map_var[i] = count;
|
|
count += k;
|
|
}
|
|
else {
|
|
map_var[i] = count;
|
|
for(j=0; j<num_targets; j++)
|
|
if(yes_vecs[j][i]> 0) {
|
|
yes_nc += k;
|
|
map_var[i] = count;
|
|
yes_count ++; // each target state has one extra action
|
|
count += k+1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
num_lp_vars = maybe_nc + yes_nc + yes_count;
|
|
map_var[n] = num_lp_vars; // maybe need to be modified.
|
|
PS_PrintToMainLog(env, "Number of LP variables = %1d\n", num_lp_vars);
|
|
|
|
for(i=0; i<n; i++)
|
|
yes_vec[i] = 0;
|
|
count = 0;
|
|
for(i=0; i<n; i++)
|
|
for(j=0; j<num_targets; j++)
|
|
if(yes_vecs[j][i]> 0) { // For each state, count the number of targets it belongs to.
|
|
yes_vec[i]++;
|
|
count++;
|
|
}
|
|
|
|
/*printf("map_var = ");
|
|
for(i=0; i<=n; i++)
|
|
printf(" %1d", map_var[i]);
|
|
printf("\n");
|
|
fflush(stdout);*/
|
|
|
|
h1 = h2 = 0;
|
|
for(i=0; i<n; i++)
|
|
arr_ints[i] = map_var[i+1]-map_var[i];
|
|
for (i = 0; i < n; i++) {
|
|
if (!use_counts) {
|
|
l1 = row_starts[i];
|
|
h1 = row_starts[i+1];
|
|
} else {
|
|
l1 = h1;
|
|
h1 += row_counts[i];
|
|
}
|
|
for (j = l1; j < h1; j++) { // j: choice index; x+j: variable index
|
|
if (!use_counts) {
|
|
l2 = choice_starts[j];
|
|
h2 = choice_starts[j+1];
|
|
} else {
|
|
l2 = h2;
|
|
h2 += choice_counts[j];
|
|
}
|
|
if(h2-l2>1 || cols[l2] != i || non_zeros[l2]!=1.0) {
|
|
if (maybe_vec[i]> 0 || yes_vec[i]> 0)
|
|
for(k=l2; k<h2; k++) {
|
|
if(maybe_vec[cols[k]]> 0 || yes_vec[cols[k]]> 0)
|
|
arr_ints[cols[k]] ++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//int *constraints_ints[n];
|
|
//double *constraints_reals[n];
|
|
int *constraints_sp;
|
|
//int constraints_sp[n];
|
|
int *constraints_ints;
|
|
double *constraints_reals;
|
|
unsigned long *constraints_int_ptr;
|
|
unsigned long *constraints_real_ptr;
|
|
//PS_PrintToMainLog(env, "Allocating memory space \n");
|
|
constraints_sp = new int[n];
|
|
constraints_int_ptr = new unsigned long[n];
|
|
constraints_real_ptr = new unsigned long[n];
|
|
for(i=0; i<n; i++)
|
|
if(maybe_vec[i]> 0 || yes_vec[i]> 0) {
|
|
//printf("i = %1d, ", i);
|
|
constraints_ints = new int[arr_ints[i]];
|
|
constraints_reals = new REAL[arr_ints[i]];
|
|
constraints_sp[i] = map_var[i+1]-map_var[i];
|
|
constraints_int_ptr[i] = (unsigned long)constraints_ints;
|
|
constraints_real_ptr[i] = (unsigned long)constraints_reals;
|
|
for(j=0; j<map_var[i+1]-map_var[i]; j++) {
|
|
constraints_ints[j] = map_var[i] + j;
|
|
constraints_reals[j] = 1.0;
|
|
}
|
|
for(j=map_var[i+1]-map_var[i]; j<arr_ints[i]; j++) {
|
|
constraints_ints[j] = -1;
|
|
constraints_reals[j] = 0;
|
|
}
|
|
|
|
//printf("arr_ints[%1d] = %1d\n", i, arr_ints[i]);
|
|
}
|
|
|
|
//if (arr_reals) delete[] arr_reals;
|
|
arr_reals = new REAL[num_lp_vars];
|
|
|
|
// create map vector
|
|
/*count = 0;
|
|
for(i=0; i<n; i++) {
|
|
if(yes_vec[i] > 0 || maybe_vec[i] > 0) {
|
|
map_var[i] = count;
|
|
count += use_counts ? row_counts[i] : (row_starts[i+1] - row_starts[i]);
|
|
if(yes_vec[i] > 0)
|
|
count ++; // Add extra transition
|
|
} else
|
|
map_var[i] = count;
|
|
}
|
|
map_var[n] = num_lp_vars; // maybe need to be modified.*/
|
|
|
|
/* write the LP to file LP.ecl */
|
|
/*f = fopen("LP.ecl", "w"); /* create a file for writing * /
|
|
|
|
if(f==NULL)
|
|
PS_PrintToMainLog(env, "Cannot create LP.ecl!\n");
|
|
|
|
fprintf(f, ":- lib(eplex).\n\n");
|
|
fprintf(f, "main1(Cost, Vars) :-\n");
|
|
fprintf(f, "Vars = [");
|
|
for(i=0; i<num_lp_vars; i++) {
|
|
if(i>0)
|
|
fprintf(f, ", ");
|
|
fprintf(f, "X%1d", i+1);
|
|
}
|
|
|
|
fprintf(f, "],\n");
|
|
fprintf(f, "Vars :: 0.0..inf,\n\n");*/
|
|
|
|
/*printf("map_var = ");
|
|
for(i=0; i<=n; i++)
|
|
printf(" %1d", map_var[i]);
|
|
printf("\n");
|
|
fflush(stdout);*/
|
|
|
|
// Initialize ECLiPSe
|
|
ec_init();
|
|
|
|
// Load Eplex library
|
|
ec_post_string("lib(eplex)");
|
|
|
|
// Create ECLiPSe variables
|
|
Vars = ec_refs_create_newvars(num_lp_vars);
|
|
Cost = ec_ref_create_newvar();
|
|
varlist = ec_listofrefs(Vars);
|
|
|
|
// Define the domain of the variables
|
|
ec_post_goal(ec_term(
|
|
ec_did("::",2),
|
|
varlist,
|
|
ec_term(ec_did("..",2), ec_double(0.0), ec_double(1e20))));
|
|
|
|
stop = util_cpu_time();
|
|
time_for_setup = (double)(stop - start3)/1000;
|
|
start2 = stop;
|
|
|
|
// Add constraints to LP problem
|
|
int x;
|
|
//h1 = h2 = 0;
|
|
/*for (i = 0; i < n; i++) {
|
|
// Add constraints for maybe and target states
|
|
if (maybe_vec[i] > 0 || yes_vec[i] > 0)
|
|
for (j = 0; j < map_var[i+1]-map_var[i]; j++) {// \Sigma_{v\in V/F} y_{(v, \gamma)}
|
|
printf("constraints_ints[%1d][%1d] = %1d, ", i, j, constraints_ints[i][j]);
|
|
printf("constraints_reals[%1d][%1d] = %g\n", i, j, constraints_reals[i][j]);
|
|
}
|
|
printf("constraints_sp[%1d] = %1d\n\n", i, constraints_sp[i]);
|
|
}*/
|
|
|
|
//count = map_var[i+1] - map_var[i];
|
|
h1 = h2 = 0;
|
|
for (x = 0; x < n; x++) { // h2: row index
|
|
if(maybe_vec[x]> 0 || yes_vec[x]> 0) {
|
|
if (!use_counts) {
|
|
l1 = row_starts[x];
|
|
h1 = row_starts[x+1];
|
|
} else {
|
|
l1 = h1;
|
|
h1 += row_counts[x];
|
|
}
|
|
count = 0;
|
|
for (j = l1; j < h1; j++) { // j: choice index; x+j: variable index
|
|
if (!use_counts) {
|
|
l2 = choice_starts[j];
|
|
h2 = choice_starts[j+1];
|
|
} else {
|
|
l2 = h2;
|
|
h2 += choice_counts[j];
|
|
}
|
|
if(h2-l2==1 && cols[l2] == x)
|
|
count++;
|
|
else
|
|
for(k=l2; k<h2; k++) { // k: column index
|
|
// get the index of the corresponding variable
|
|
i = cols[k];
|
|
if(maybe_vec[i]> 0 || yes_vec[i]> 0) {
|
|
//printf(" x = %1d, i = %1d, nonzeros = %g, j = %1d, l1 = %1d, count = %1d, map_var[x]+j-l1-count = %1d\n",
|
|
// x, i, non_zeros[k], j, l1, count, map_var[x]+j-l1-count);
|
|
constraints_ints = (int *)constraints_int_ptr[i];
|
|
constraints_reals = (double *)constraints_real_ptr[i];
|
|
for(k_r=0; k_r<constraints_sp[i]; k_r++)
|
|
if(constraints_ints[k_r]==map_var[x]+j-l1-count)
|
|
break;
|
|
|
|
if(k_r == constraints_sp[i]) {
|
|
//count++;
|
|
constraints_ints[k_r]=map_var[x]+j-l1-count;
|
|
constraints_reals[k_r] = -non_zeros[k];
|
|
constraints_sp[i]++;
|
|
} else {
|
|
constraints_reals[k_r] -= non_zeros[k];
|
|
if(constraints_reals[k_r] == 0.0) { // In fact, this cannot happen.
|
|
//count--;
|
|
for(l2_r=k_r; l2_r<constraints_sp[i]-1; l2_r++) {
|
|
constraints_reals[l2_r] = constraints_reals[l2_r+1];
|
|
constraints_ints[l2_r] = constraints_ints[l2_r+1];
|
|
}
|
|
constraints_sp[i]--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if(use_counts) {
|
|
l1 = h1;
|
|
h1 += row_counts[x];
|
|
for (j = l1; j < h1; j++)
|
|
h2 += choice_counts[j];
|
|
}
|
|
}
|
|
|
|
/*fprintf(f, " ");
|
|
l2 = 0;
|
|
for (k = 0; k < num_lp_vars; k++)
|
|
if(arr_reals[k] != 0) {
|
|
if(arr_reals[k] > 0 && l2 > 0)
|
|
fprintf(f, "+");
|
|
fprintf(f, "%g*X%1d", arr_reals[k], k+1);
|
|
l2++;
|
|
}
|
|
fprintf(f, " $= %g,\n", (start_index==i ? 1.0 : 0.0));
|
|
//printf(" count = %1d\n", count);
|
|
fflush(f);*/
|
|
|
|
//pword tail = ec_nil();
|
|
//x = 0;
|
|
|
|
/*for(k=num_lp_vars-1; k>=0; k--)
|
|
if(arr_reals[k] != 0.0)
|
|
tail = ec_list(ec_refs_get(Vars, k), tail);
|
|
for(k=0; k<num_lp_vars; k++)
|
|
if(arr_reals[k] != 0.0)
|
|
arr_reals[x++] = arr_reals[k];*/
|
|
/*printf("arr_reals & arr_ints = ");
|
|
for(k=0; k<sp; k++) {
|
|
printf("(%1d, %g) ", arr_ints[k], arr_reals[k]);
|
|
}
|
|
printf("\n");*/
|
|
|
|
/*for(k=sp-1; k>=0; k--)
|
|
tail = ec_list(ec_refs_get(Vars, arr_ints[k]), tail);
|
|
ec_post_goal(ec_term(ec_did(("$="),2),
|
|
ec_term(ec_did("*",2),
|
|
tail,
|
|
ec_listofdouble(sp, arr_reals)),
|
|
ec_double((start_index==i ? 1.0 : 0.0))));*/
|
|
/*ec_post_goal(ec_term(ec_did(("$="),2),
|
|
ec_term(ec_did("*",2),
|
|
varlist,
|
|
ec_listofdouble(num_lp_vars, arr_reals)),
|
|
ec_double((start_index==i ? 1.0 : 0.0))));*/
|
|
//printf("output LP constraints to ECLiSPe\n");
|
|
for (i = 0; i < n; i++)
|
|
if (maybe_vec[i]> 0 || yes_vec[i]> 0) {
|
|
constraints_ints = (int *)constraints_int_ptr[i];
|
|
constraints_reals = (double *)constraints_real_ptr[i];
|
|
pword tail = ec_nil();
|
|
for(k=constraints_sp[i]-1; k>=0; k--)
|
|
tail = ec_list(ec_refs_get(Vars, constraints_ints[k]), tail);
|
|
ec_post_goal(ec_term(ec_did(("$="),2),
|
|
ec_term(ec_did("*",2),
|
|
tail,
|
|
ec_listofdouble(constraints_sp[i], constraints_reals)),
|
|
ec_double((start_index==i ? 1.0 : 0.0))));
|
|
/*printf("i =%1d, constrains_sp = %1d, ", i, constraints_sp[i]);
|
|
for(k=0; k<constraints_sp[i]; k++)
|
|
printf("(%1d, %g) ", constraints_ints[i][k], constraints_reals[i][k]);
|
|
printf("\n");*/
|
|
delete[] constraints_ints;
|
|
delete[] constraints_reals;
|
|
}
|
|
delete[] constraints_sp;
|
|
delete[] constraints_int_ptr;
|
|
delete[] constraints_real_ptr;
|
|
PS_PrintToMainLog(env, "Adding extra constraints for probabilisitic bounds\n");
|
|
for(i=0; i<num_targets; i++) {
|
|
if(relops[i]==0 || relops[i]>2)
|
|
continue;
|
|
//PS_PrintToMainLog(env, "num_map = %1d, i = %1d, bound = %1.1f\n", num_map, i, bounds[i]);
|
|
for(k=0; k<num_lp_vars; k++)
|
|
arr_reals[k] = 0.0;
|
|
|
|
count = 0; // count the number of extra transitions for the i_th target
|
|
for(k=0; k<n; k++)
|
|
if(yes_vecs[i][k]> 0) {
|
|
arr_reals[map_var[k+1]-1] = 1.0;
|
|
count++;
|
|
}
|
|
|
|
/*fprintf(f, " ");
|
|
l2 = 0;
|
|
for (k = 0; k < num_lp_vars; k++)
|
|
if(arr_reals[k] != 0) {
|
|
if(arr_reals[k] > 0 && l2 > 0)
|
|
fprintf(f, "+");
|
|
fprintf(f, "%g*X%1d", arr_reals[k], k+1);
|
|
l2++;
|
|
}
|
|
fprintf(f, " $>= %g,\n", bounds[i]);
|
|
fflush(f);*/
|
|
|
|
pword tail = ec_nil();
|
|
x = 0;
|
|
|
|
for(k=num_lp_vars-1; k>=0; k--)
|
|
if(arr_reals[k] != 0.0)
|
|
tail = ec_list(ec_refs_get(Vars, k), tail);
|
|
for(k=0; k<num_lp_vars; k++)
|
|
if(arr_reals[k] != 0.0)
|
|
arr_reals[x++] = arr_reals[k];
|
|
ec_post_goal(ec_term(ec_did(("$>="),2),
|
|
ec_term(ec_did("*",2),
|
|
tail,
|
|
ec_listofdouble(count, arr_reals)),
|
|
ec_double(bounds[i])));
|
|
|
|
/*ec_post_goal(ec_term(ec_did(("$="),2),
|
|
ec_term(ec_did("*",2),
|
|
varlist,
|
|
ec_listofdouble(num_lp_vars, arr_reals)),
|
|
ec_double(0.0)));*/
|
|
}
|
|
|
|
// Adding constraints for rewards
|
|
/*if(relops[0] > 2) {
|
|
for(i=0; i<num_lp_vars; i++)
|
|
arr_reals[i] = 0;
|
|
|
|
h1 = h2 = h2_r = 0;
|
|
for(i=0; i<n; i++)
|
|
if(maybe_vec_r[i] > 0) {
|
|
for(j=num_lp_vars; j<num_lp_vars + n_maybe_r; j++)
|
|
arr_reals[j] = 0;
|
|
arr_reals[map_var_r[i]+num_lp_vars] = 1.0;
|
|
|
|
if (!use_counts) { // assume we always do not use counts
|
|
l1 = row_starts[i];
|
|
h1 = row_starts[i+1];
|
|
} else { // Problematic
|
|
l1 = h1;
|
|
h1 += row_counts[i];
|
|
}
|
|
for (j = l1; j < h1; j++) {// \Sigma_{v\in V/F} y_{(v, \gamma)}
|
|
if (!use_counts) {
|
|
l2 = choice_starts[j];
|
|
h2 = choice_starts[j+1];
|
|
} else {
|
|
l2 = h2;
|
|
h2 += choice_counts[j];
|
|
}
|
|
if (!use_counts_r) {
|
|
l2_r = choice_starts_r[j];
|
|
h2_r = choice_starts_r[j+1];
|
|
} else {
|
|
l2_r = h2_r;
|
|
h2_r += choice_counts_r[j];
|
|
}
|
|
for (k = l2; k < h2; k++) {
|
|
// find corresponding transition reward if any
|
|
// Hongyang: Can it be simplified?
|
|
k_r = l2_r;
|
|
while (k_r < h2_r && cols_r[k_r] != cols[k])
|
|
k_r++;
|
|
// if there is one, add reward * prob to reward value
|
|
if (k_r < h2_r && (maybe_vec[cols[k]] > 0 || yes_vecs[0][cols[k]] > 0)) {
|
|
arr_reals[map_var[i]+j-l1] -= non_zeros_r[k_r] * non_zeros[k];
|
|
if(maybe_vec[cols[k]] > 0)
|
|
arr_reals[map_var_r[cols[k]]+num_lp_vars] -= non_zeros[k_r];
|
|
}
|
|
}
|
|
|
|
}
|
|
printf(" arr_reals:");
|
|
for (k = 0; k < num_lp_vars+n_maybe_r; k++)
|
|
printf(" %1.1f", arr_reals[k]);
|
|
printf(" = 0\n");
|
|
fflush(stdout);
|
|
|
|
pword tail = ec_nil();
|
|
x = 0;
|
|
|
|
for(k=num_lp_vars+n_maybe_r-1; k>=0; k--)
|
|
if(arr_reals[k] != 0.0)
|
|
tail = ec_list(ec_refs_get(Vars, k), tail);
|
|
for(k=0; k<num_lp_vars+n_maybe_r; k++)
|
|
if(arr_reals[k] != 0.0)
|
|
arr_reals[x++] = arr_reals[k];
|
|
ec_post_goal(ec_term(ec_did(("$="),2),
|
|
ec_term(ec_did("*",2),
|
|
tail,
|
|
ec_listofdouble(x, arr_reals)),
|
|
ec_double(0.0)));
|
|
|
|
}
|
|
}*/
|
|
|
|
PS_PrintToMainLog(env, "Computing optimisation...\n");
|
|
fflush(stdout);
|
|
pword tail = ec_nil();
|
|
x = 0;
|
|
if(relops[0]> 0 && relops[0]<=2) {
|
|
//fprintf(f, " optimize(max(");
|
|
//l2 = 0;
|
|
for(i=0; i<n; i++)
|
|
if(yes_vec[i]> 0) {
|
|
tail = ec_list(ec_refs_get(Vars, map_var[i+1]-1), tail);
|
|
arr_reals[x++] = 1.0;
|
|
//if(l2 > 0)
|
|
// fprintf(f, "+");
|
|
//fprintf(f, "X%1d", map_var[i+1]);
|
|
//l2++;
|
|
}
|
|
//fprintf(f, "), Cost).\n");
|
|
//fflush(f);
|
|
} else if(relops[0] == 0) {
|
|
//fprintf(f, " optimize(max(");
|
|
//l2 = 0;
|
|
for(i=0; i<n; i++)
|
|
if(yes_vecs[0][i]> 0) {
|
|
tail = ec_list(ec_refs_get(Vars, map_var[i+1]-1), tail);
|
|
arr_reals[x++] = 1.0;
|
|
//if(l2 > 0)
|
|
// fprintf(f, "+");
|
|
//fprintf(f, "X%1d", map_var[i+1]);
|
|
//l2++;
|
|
}
|
|
//fprintf(f, "), Cost).\n");
|
|
//fflush(f);
|
|
} else {
|
|
/*x = 1;
|
|
arr_reals[0] = 1.0;
|
|
tail = ec_list(ec_refs_get(Vars, map_var_r[start_index]+num_lp_vars), tail);*/
|
|
PS_PrintToMainLog(env, "computing max function for rewards ...\n");
|
|
double *non_zeros_r;
|
|
unsigned char *choice_counts_r;
|
|
int *choice_starts_r;
|
|
bool use_counts_r;
|
|
unsigned int *cols_r;
|
|
trans_rewards = jlong_to_DdNode(trr); // transition rewards
|
|
Cudd_Ref(trans_rewards);
|
|
trans_rewards = DD_Apply(ddman, APPLY_TIMES, trans_rewards, maybe);
|
|
PS_PrintToMainLog(env, "Building sparse matrix (transition rewards)... ");
|
|
ndsm_r = build_sub_nd_sparse_matrix(ddman, a, trans_rewards, rvars, cvars, num_rvars, ndvars, num_ndvars, odd);
|
|
nnz_r = ndsm_r->nnz;
|
|
nc_r = ndsm_r->nc;
|
|
// print out info
|
|
PS_PrintToMainLog(env, "[n=%d, nc=%d, nnz=%d, k=%d] ", n, nc_r, nnz_r, ndsm_r->k);
|
|
kb = (nnz_r*12.0+nc_r*4.0+n*4.0)/1024.0;
|
|
kbt += kb;
|
|
PS_PrintMemoryToMainLog(env, "[", kb, "]\n");
|
|
non_zeros_r = ndsm_r->non_zeros;
|
|
choice_counts_r = ndsm_r->choice_counts;
|
|
choice_starts_r = (int *)ndsm_r->choice_counts;
|
|
use_counts_r = ndsm_r->use_counts;
|
|
cols_r = ndsm_r->cols;
|
|
|
|
for(i=0; i<num_lp_vars; i++)
|
|
arr_reals[i] = 0;
|
|
|
|
h1 = h2 = l2_r = h2_r = 0;
|
|
for(i=0; i<n; i++)
|
|
if(maybe_vec[i]> 0) {
|
|
if (!use_counts) { // assume we always do not use counts
|
|
l1 = row_starts[i];
|
|
h1 = row_starts[i+1];
|
|
} else { // Problematic
|
|
l1 = h1;
|
|
h1 += row_counts[i];
|
|
}
|
|
for (j = l1; j < h1; j++) {// \Sigma_{v\in V/F} y_{(v, \gamma)}*c_{(v, \gamma)}
|
|
if (!use_counts) {
|
|
l2 = choice_starts[j];
|
|
h2 = choice_starts[j+1];
|
|
} else {
|
|
l2 = h2;
|
|
h2 += choice_counts[j];
|
|
}
|
|
if (!use_counts_r) {
|
|
l2_r = choice_starts_r[j];
|
|
h2_r = choice_starts_r[j+1];
|
|
} else {
|
|
l2_r = h2_r;
|
|
h2_r += choice_counts_r[j];
|
|
}
|
|
k_r = l2_r;
|
|
while (k_r < h2_r && cols_r[k_r] != cols[l2])
|
|
k_r++;
|
|
// if there is one, add reward * prob to reward value
|
|
if (k_r < h2_r) {
|
|
arr_reals[map_var[i]+j-l1] = non_zeros_r[k_r];
|
|
}
|
|
}
|
|
} else if(use_counts) { // count the number of choices for non maybe nodes. Is it necessary?
|
|
l1 = h1;
|
|
h1 += row_counts[i];
|
|
for (j = l1; j < h1; j++) {
|
|
h2 += choice_counts[j];
|
|
h2_r += choice_counts_r[j];
|
|
}
|
|
}
|
|
/*PS_PrintToMainLog(env, " arr_reals:");
|
|
for (k = 0; k < num_lp_vars; k++)
|
|
PS_PrintToMainLog(env, " %1.1f", arr_reals[k]);
|
|
PS_PrintToMainLog(env, "\n");
|
|
fflush(stdout);*/
|
|
|
|
for(k=num_lp_vars-1; k>=0; k--)
|
|
if(arr_reals[k] != 0.0)
|
|
tail = ec_list(ec_refs_get(Vars, k), tail);
|
|
for(k=0; k<num_lp_vars; k++)
|
|
if(arr_reals[k] != 0.0)
|
|
arr_reals[x++] = arr_reals[k];
|
|
}
|
|
ec_post_goal( ec_term(ec_did("optimize", 2),
|
|
ec_term(ec_did("max", 1),
|
|
ec_term(ec_did("*",2), tail, ec_listofdouble(x, arr_reals))),
|
|
ec_ref_get(Cost)));
|
|
/*ec_post_goal( ec_term(ec_did("optimize", 2),
|
|
ec_term(ec_did("max", 1),
|
|
ec_term(ec_did("*",2), varlist, ec_listofdouble(num_lp_vars, pc))),
|
|
ec_ref_get(Cost)));*/
|
|
//fclose(f);
|
|
}
|
|
|
|
/* write the produce mdp to file model.dot */
|
|
printf("Writing the model to model.dot\n"); fflush(stdout);
|
|
|
|
f = fopen("model.dot", "w"); /* create a file for writing */
|
|
f = NULL;
|
|
if(f==NULL) {
|
|
PS_PrintToMainLog(env, "\nWarning: Output of graph cancelled (could not open file \"%s\").\n", "model.dot");
|
|
} else {
|
|
fprintf(f, "digraph model {\n");
|
|
for(i=0; i<n; i++)
|
|
if(i == start_index)
|
|
fprintf(f, " %1d [label=\"%1d\", shape=ellipse]\n", i, i);
|
|
else if(yes_vec[i]> 0)
|
|
fprintf(f, " %1d [label=\"%1d\", shape=doublecircle]\n", i, i);
|
|
else
|
|
fprintf(f, " %1d [label=\"%1d\", shape=circle]\n", i, i);
|
|
count = n; l1 = h1 = l2 = h2 = 0;
|
|
for(i=0; i<n; i++) {
|
|
if (!use_counts) {
|
|
l1 = row_starts[i];
|
|
h1 = row_starts[i+1];
|
|
} else {
|
|
l1 = h1;
|
|
h1 += row_counts[i];
|
|
}
|
|
for (j = l1; j < h1; j++) {
|
|
if (!use_counts) {
|
|
l2 = choice_starts[j];
|
|
h2 = choice_starts[j+1];
|
|
} else {
|
|
l2 = h2;
|
|
h2 += choice_counts[j];
|
|
}
|
|
if(h2-l2>1) {
|
|
fprintf(f, " %1d [label=\"\", shape=point]\n", count);
|
|
fprintf(f, " %1d -> %1d\n", i, count);
|
|
for(k=l2; k<h2; k++)
|
|
fprintf(f, " %1d -> %1d [label=\"%g\"]\n", count,
|
|
cols[k], non_zeros[k]);
|
|
count ++;
|
|
} else
|
|
fprintf(f, " %1d -> %1d [label=\"%g\"]\n", i,
|
|
cols[l2], non_zeros[l2]);
|
|
}
|
|
}
|
|
fprintf(f, "}\n");
|
|
fclose(f);
|
|
}
|
|
|
|
// Get the result from the solver
|
|
if (ec_resume1(0) == PSUCCEED) { /* solve */
|
|
stop = util_cpu_time();
|
|
if (ec_get_double(ec_ref_get(Cost), &lp_result) == PSUCCEED)
|
|
PS_PrintToMainLog(env, "Cost is %g\n", lp_result);
|
|
else
|
|
PS_PrintToMainLog(env, "Cost is ?\n");
|
|
|
|
double *var_values;
|
|
var_values = new double[num_lp_vars+n_maybe_r];
|
|
count = 0;
|
|
for (i=0; i<num_lp_vars+n_maybe_r; i++) {
|
|
var_values[i] = 0.0;
|
|
if (ec_get_double(ec_refs_get(Vars,i), &var_values[i]) == PSUCCEED) {
|
|
if(var_values[i] != 0) {
|
|
PS_PrintToMainLog(env, "X%d = %g ", i, var_values[i]);
|
|
count++;
|
|
}
|
|
}
|
|
//else
|
|
// PS_PrintToMainLog(env, "X%d = ? ");
|
|
if(count == 8) {
|
|
PS_PrintToMainLog(env, "\n");
|
|
count = 0;
|
|
}
|
|
}
|
|
if(count)
|
|
PS_PrintToMainLog(env, "\n");
|
|
|
|
/***********************************************************************
|
|
*
|
|
*
|
|
* generate adversary according the solution
|
|
*
|
|
*
|
|
***********************************************************************/
|
|
char c = '\0';
|
|
/*if(n < 100) {
|
|
printf("Would you like to see the adversary (Y/N)\n"); fflush(stdout);
|
|
while (1) {
|
|
scanf("%c", &c);
|
|
if(c == 'Y' || c == 'y' || c == 'N' || c == 'n')
|
|
break;
|
|
}
|
|
}*/
|
|
c = 'n';
|
|
|
|
if(c == 'Y' || c == 'y') {
|
|
long sp_nodes = 0; // pointer of dot nodes
|
|
long extra_node = n; // index of intermediate nodes for actions
|
|
long sp_edges = 0; // pointer of dot edges
|
|
//int queue[n]; // search queue
|
|
int *queue;
|
|
long head = 0; // pointer to the head of the queue
|
|
long tail = 0; // pointer to the tail of the queue
|
|
//int nodes[n]; // indicate whether the node has been visited
|
|
int *nodes;
|
|
|
|
queue = new int[n];
|
|
nodes = new int[n];
|
|
for(i=0; i<n; i++)
|
|
nodes[i] = 0;
|
|
|
|
if(checkReach) {// Adversary for reachability
|
|
int (*dot_nodes)[2];
|
|
int (*dot_edges)[2];
|
|
double *edge_probabilities;
|
|
//printf("allocated memory for local variables:\n");
|
|
//printf("n=%1d, num_lp_vars=%1d, nnz=%1d\n", n, num_lp_vars, nnz);
|
|
//fflush(stdout);
|
|
|
|
//int dot_nodes[n+num_lp_vars][2]; // first entry: node number, second: shape
|
|
//int dot_edges[nnz+num_lp_vars][2]; // first entry: source node, second: target
|
|
//double edge_probabilities[nnz+num_lp_vars]; // edge's probability
|
|
|
|
dot_nodes = new int[n+num_lp_vars][2];
|
|
dot_edges = new int[nnz+num_lp_vars][2];
|
|
edge_probabilities = new double[nnz+num_lp_vars];
|
|
//int dot_nodes[n+maybe_nc][2]; // first entry: node number, second: shape
|
|
//int dot_edges[nnz+maybe_nc][2]; // first entry: source node, second: target
|
|
//double edge_probabilities[nnz+maybe_nc]; // edge's probability
|
|
|
|
// put the initial state in the queue and dot_nodes
|
|
queue[tail++] = start_index;
|
|
dot_nodes[sp_nodes][0] = start_index;
|
|
dot_nodes[sp_nodes++][1] = 0; // shape = 0: ellipse, 1: circle, 2: point, 3: doublecircle
|
|
|
|
// recursive procedure
|
|
int head_node = -1;
|
|
while(head < tail) {
|
|
head_node = queue[head++];
|
|
nodes[head_node] = 1;
|
|
// If the head node is a target state, do nothing
|
|
if(yes_vec[head_node] == 0 && maybe_vec[head_node]> 0.0) {
|
|
// the number of branches in the current state
|
|
h1 = map_var[head_node+1] - map_var[head_node];
|
|
//PS_PrintToMainLog(env, "h1 = %1d\n", h1);
|
|
|
|
double sum = 0;
|
|
for(i=0; i<h1; i++)
|
|
sum += var_values[map_var[head_node] + i];
|
|
|
|
for(i=0; i<h1; i++)
|
|
// test if the action has non-zero probability
|
|
if(var_values[map_var[head_node] + i]> 0) {
|
|
// get all successor states of this action
|
|
// First: locate the action
|
|
if (!use_counts) {
|
|
l1 = row_starts[head_node];
|
|
} else {
|
|
l1 = 0;
|
|
for(j=0; j<head_node; j++)
|
|
l1 += row_counts[j];
|
|
}
|
|
l1 += i;
|
|
|
|
// Second: find all columns for this choice
|
|
if (!use_counts) {
|
|
l2 = choice_starts[l1];
|
|
h2 = choice_starts[l1+1];
|
|
} else {
|
|
l2 = 0;
|
|
for(j=0; j<l1; j++)
|
|
l2 += choice_counts[j];
|
|
h2 = l2 + choice_counts[j];
|
|
}
|
|
|
|
if(h2-l2>1) {
|
|
// add an intermediate node to dot_nodes
|
|
dot_nodes[sp_nodes][0] = extra_node;
|
|
dot_nodes[sp_nodes++][1] = 2;
|
|
// add an edge to dot_edges
|
|
dot_edges[sp_edges][0] = head_node;
|
|
dot_edges[sp_edges][1] = extra_node;
|
|
// add the probability to the edge
|
|
edge_probabilities[sp_edges++] = sum == 1 ? var_values[map_var[head_node] + i] :
|
|
var_values[map_var[head_node] + i]/sum;
|
|
|
|
for(j=l2; j<h2; j++) {
|
|
// add the successor state to dot_nodes
|
|
dot_nodes[sp_nodes][0] = cols[j];
|
|
if(yes_vec[cols[j]]> 0)
|
|
dot_nodes[sp_nodes++][1] = 3;
|
|
else
|
|
dot_nodes[sp_nodes++][1] = 1;
|
|
|
|
// add an edge to dot_edges
|
|
dot_edges[sp_edges][0] = extra_node;
|
|
dot_edges[sp_edges][1] = cols[j];
|
|
// add the probability to the edge
|
|
edge_probabilities[sp_edges++] = non_zeros[j];
|
|
|
|
if(maybe_vec[cols[j]]> 0 && nodes[cols[j]] == 0)
|
|
queue[tail++] = cols[j];
|
|
}
|
|
extra_node++;
|
|
} else {
|
|
// add the successor state to dot_nodes
|
|
dot_nodes[sp_nodes][0] = cols[l2];
|
|
if(yes_vec[cols[l2]]> 0)
|
|
dot_nodes[sp_nodes++][1] = 3;
|
|
else
|
|
dot_nodes[sp_nodes++][1] = 1;
|
|
// add an edge to dot_edges
|
|
dot_edges[sp_edges][0] = head_node;
|
|
dot_edges[sp_edges][1] = cols[l2];
|
|
// add the probability to the edge
|
|
//edge_probabilities[sp_edges++] = var_values[map_var[head_node] + i];
|
|
edge_probabilities[sp_edges++] = sum == 1 ? var_values[map_var[head_node] + i] :
|
|
var_values[map_var[head_node] + i]/sum;
|
|
|
|
if(maybe_vec[cols[l2]]> 0 && nodes[cols[l2]] == 0)
|
|
queue[tail++] = cols[l2];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// write to file
|
|
f = fopen("adversary.dot", "w"); /* create a file for writing */
|
|
f = NULL;
|
|
if(f==NULL) {
|
|
PS_PrintToMainLog(env, "\nWarning: Output of adversary cancelled (could not open file \"%s\").\n", "adversary.dot");
|
|
} else {
|
|
fprintf(f, "digraph adversary {\n");
|
|
for(i=0; i<sp_nodes; i++)
|
|
if(dot_nodes[i][0] >= n)
|
|
fprintf(f, " %1d [label=\"\", shape=point]\n", dot_nodes[i][0]);
|
|
else
|
|
fprintf(f, " %1d [label=\"%1d\", shape=%s]\n", dot_nodes[i][0],
|
|
dot_nodes[i][0],
|
|
((dot_nodes[i][1]==0)? "ellipse" :
|
|
((dot_nodes[i][1]==1)? "circle" : "doublecircle")));
|
|
for(i=0; i<sp_edges; i++)
|
|
fprintf(f, " %1d -> %1d [label=\"%g\"]\n", dot_edges[i][0],
|
|
dot_edges[i][1], edge_probabilities[i]);
|
|
fprintf(f, "}\n");
|
|
fclose(f);
|
|
}
|
|
} else {// Adversary for LTL formulas
|
|
int (*dot_nodes)[2];
|
|
int (*dot_edges)[2];
|
|
double *edge_probabilities;
|
|
int *terminate_nodes;
|
|
//printf("allocated memory for local variables:\n");
|
|
//printf("n=%1d, num_lp_vars=%1d, nnz=%1d\n", n, num_lp_vars, nnz);
|
|
//fflush(stdout);
|
|
|
|
//int dot_nodes[n+num_lp_vars][2]; // first entry: node number, second: shape
|
|
//int dot_edges[nnz+num_lp_vars][2]; // first entry: source node, second: target
|
|
//double edge_probabilities[nnz+num_lp_vars]; // edge's probability
|
|
|
|
dot_nodes = new int[n+num_lp_vars][2];
|
|
dot_edges = new int[nnz+num_lp_vars][2];
|
|
edge_probabilities = new double[nnz+num_lp_vars];
|
|
terminate_nodes = new int[n]; // the entry stores the node number for newly added terminate nodes
|
|
|
|
//printf("Done\n");
|
|
//fflush(stdout);
|
|
|
|
for(i=0; i<n; i++)
|
|
terminate_nodes[i] = -1;
|
|
|
|
// put the initial state in the queue and dot_nodes
|
|
queue[tail++] = start_index;
|
|
dot_nodes[sp_nodes][0] = start_index;
|
|
dot_nodes[sp_nodes++][1] = 0; // shape = 0: ellipse, 1: circle, 2: point, 3: doublecircle, 4: box
|
|
|
|
// recursive procedure
|
|
int head_node = -1;
|
|
while(head < tail) {
|
|
head_node = queue[head++];
|
|
|
|
if(nodes[head_node] == 1)
|
|
continue;
|
|
nodes[head_node] = 1;
|
|
// If the head node is a target state, do nothing
|
|
if(yes_vec[head_node]> 0 || maybe_vec[head_node]> 0) {
|
|
// the number of branches in the current state
|
|
h1 = map_var[head_node+1] - map_var[head_node];
|
|
|
|
double sum = 0;
|
|
for(i=0; i<h1; i++)
|
|
sum += var_values[map_var[head_node] + i];
|
|
|
|
for(i=0; i<h1; i++)
|
|
// test if the action has non-zero probability
|
|
if(var_values[map_var[head_node] + i]> 0) {
|
|
if(yes_vec[head_node]> 0 && i==h1-1) { // extra transition
|
|
// add an intermediate node to dot_nodes
|
|
if(terminate_nodes[head_node] < 0) {
|
|
dot_nodes[sp_nodes][0] = extra_node;
|
|
dot_nodes[sp_nodes++][1] = 4;
|
|
dot_edges[sp_edges][1] = extra_node;
|
|
terminate_nodes[head_node] = extra_node;
|
|
} else
|
|
dot_edges[sp_edges][1] = terminate_nodes[head_node];
|
|
// add an edge to dot_edges
|
|
dot_edges[sp_edges][0] = head_node;
|
|
// add the probability to the edge
|
|
//edge_probabilities[sp_edges++] = var_values[map_var[head_node] + i];
|
|
edge_probabilities[sp_edges++] = sum == 1 ? var_values[map_var[head_node] + i] :
|
|
var_values[map_var[head_node] + i]/sum;
|
|
extra_node++;
|
|
} else {
|
|
// get all successor states of this action
|
|
// First: locate the action
|
|
if (!use_counts) {
|
|
l1 = row_starts[head_node];
|
|
} else {
|
|
l1 = 0;
|
|
for(j=0; j<head_node; j++)
|
|
l1 += row_counts[j];
|
|
}
|
|
l1 += i;
|
|
|
|
// Second: find all columns for this choice
|
|
if (!use_counts) {
|
|
l2 = choice_starts[l1];
|
|
h2 = choice_starts[l1+1];
|
|
} else {
|
|
l2 = 0;
|
|
for(j=0; j<l1; j++)
|
|
l2 += choice_counts[j];
|
|
h2 = l2 + choice_counts[j];
|
|
}
|
|
if(h2-l2>1) {
|
|
// add an intermediate node to dot_nodes
|
|
dot_nodes[sp_nodes][0] = extra_node;
|
|
dot_nodes[sp_nodes++][1] = 2;
|
|
// add an edge to dot_edges
|
|
dot_edges[sp_edges][0] = head_node;
|
|
dot_edges[sp_edges][1] = extra_node;
|
|
// add the probability to the edge
|
|
//edge_probabilities[sp_edges++] = var_values[map_var[head_node] + i];
|
|
edge_probabilities[sp_edges++] = sum == 1 ? var_values[map_var[head_node] + i] :
|
|
var_values[map_var[head_node] + i]/sum;
|
|
|
|
for(j=l2; j<h2; j++) {
|
|
// add the successor state to dot_nodes
|
|
dot_nodes[sp_nodes][0] = cols[j];
|
|
if(yes_vec[cols[j]]> 0)
|
|
dot_nodes[sp_nodes++][1] = 3;
|
|
else
|
|
dot_nodes[sp_nodes++][1] = 1;
|
|
|
|
// add an edge to dot_edges
|
|
dot_edges[sp_edges][0] = extra_node;
|
|
dot_edges[sp_edges][1] = cols[j];
|
|
// add the probability to the edge
|
|
edge_probabilities[sp_edges++] = non_zeros[j];
|
|
|
|
if((maybe_vec[cols[j]]> 0 || yes_vec[cols[j]]> 0) &&
|
|
nodes[cols[j]] == 0)
|
|
queue[tail++] = cols[j];
|
|
}
|
|
extra_node++;
|
|
} else {
|
|
// add the successor state to dot_nodes
|
|
dot_nodes[sp_nodes][0] = cols[l2];
|
|
if(yes_vec[cols[l2]]> 0)
|
|
dot_nodes[sp_nodes++][1] = 3;
|
|
else
|
|
dot_nodes[sp_nodes++][1] = 1;
|
|
// add an edge to dot_edges
|
|
dot_edges[sp_edges][0] = head_node;
|
|
dot_edges[sp_edges][1] = cols[l2];
|
|
// add the probability to the edge
|
|
//edge_probabilities[sp_edges++] = var_values[map_var[head_node] + i];
|
|
edge_probabilities[sp_edges++] = sum == 1 ? var_values[map_var[head_node] + i] :
|
|
var_values[map_var[head_node] + i]/sum;
|
|
|
|
if((maybe_vec[cols[l2]]> 0 || yes_vec[cols[l2]]> 0) &&
|
|
nodes[cols[l2]] == 0) {
|
|
queue[tail++] = cols[l2];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("generating adversary file\n"); fflush(stdout);
|
|
|
|
// write to file
|
|
f = fopen("adversary.dot", "w"); /* create a file for writing */
|
|
if(f==NULL) {
|
|
PS_PrintToMainLog(env, "\nWarning: Output of adversary cancelled (could not open file \"%s\").\n", "adversary.dot");
|
|
} else {
|
|
fprintf(f, "digraph adversary {\n");
|
|
for(i=0; i<sp_nodes; i++)
|
|
if(dot_nodes[i][0] >= n) {
|
|
if(dot_nodes[i][1] == 2)
|
|
fprintf(f, " %1d [label=\"\", shape=point]\n", dot_nodes[i][0]);
|
|
else
|
|
fprintf(f, " %1d [label=\"\", shape=box, fillcolor=black]\n", dot_nodes[i][0]);
|
|
} else
|
|
fprintf(f, " %1d [label=\"%1d\", shape=%s]\n", dot_nodes[i][0],
|
|
dot_nodes[i][0],
|
|
((dot_nodes[i][1]==0)? "ellipse" :
|
|
((dot_nodes[i][1]==1)? "circle" : "doublecircle")));
|
|
for(i=0; i<sp_edges; i++)
|
|
fprintf(f, " %1d -> %1d [label=\"%g\"]\n", dot_edges[i][0],
|
|
dot_edges[i][1], edge_probabilities[i]);
|
|
fprintf(f, "}\n");
|
|
fclose(f);
|
|
}
|
|
|
|
delete[] dot_nodes;
|
|
delete[] dot_edges;
|
|
delete[] edge_probabilities;
|
|
delete[] terminate_nodes;
|
|
}
|
|
|
|
delete[] queue;
|
|
delete[] nodes;
|
|
}
|
|
delete[] var_values;
|
|
}
|
|
else PS_PrintToMainLog(env, "No solution\n");
|
|
|
|
// Destroy variables and clean up
|
|
ec_refs_destroy(Vars);
|
|
ec_ref_destroy(Cost);
|
|
ec_cleanup();
|
|
|
|
//stop = util_cpu_time();
|
|
time_for_lp = (double)(stop - start2)/1000;
|
|
time_taken = (double)(stop - start3)/1000;
|
|
PS_PrintToMainLog(env, "\nCBC: LP problem solved in %.2f seconds (setup %.2f, lpsolve %.2f)\n", time_taken, time_for_setup, time_for_lp);
|
|
|
|
delete yes_vec;
|
|
delete map_var;
|
|
// catch exceptions: register error, free memory
|
|
} catch (std::bad_alloc e) {
|
|
PS_SetErrorMessage("Out of memory");
|
|
if (yes2_vec) delete[] yes2_vec;
|
|
yes2_vec = 0;
|
|
if (target_ptrs) env->ReleaseLongArrayElements(_targets, target_ptrs, 0);
|
|
if (relops) env->ReleaseIntArrayElements(_relops, relops, 0);
|
|
if (bounds) env->ReleaseDoubleArrayElements(_bounds, bounds, 0);
|
|
} catch (const char *err) {
|
|
PS_SetErrorMessage(err);
|
|
if (yes2_vec) delete yes2_vec;
|
|
yes2_vec = 0;
|
|
if (target_ptrs) env->ReleaseLongArrayElements(_targets, target_ptrs, 0);
|
|
if (relops) env->ReleaseIntArrayElements(_relops, relops, 0);
|
|
if (bounds) env->ReleaseDoubleArrayElements(_bounds, bounds, 0);
|
|
}
|
|
|
|
// free memory
|
|
if (a) Cudd_RecursiveDeref(ddman, a);
|
|
if (trans_rewards) Cudd_RecursiveDeref(ddman, trans_rewards);
|
|
if (ndsm) delete ndsm;
|
|
if (ndsm_r) delete ndsm_r;
|
|
//if (yes1_vec) delete[] yes1_vec;
|
|
delete[] maybe_vec;
|
|
for(i=0; i<num_targets; i++)
|
|
delete[] yes_vecs[i];
|
|
delete[] arr_reals;
|
|
delete[] arr_ints;
|
|
if (target_ptrs) env->ReleaseLongArrayElements(_targets, target_ptrs, 0);
|
|
if (relops) env->ReleaseIntArrayElements(_relops, relops, 0);
|
|
if (bounds) env->ReleaseDoubleArrayElements(_bounds, bounds, 0);
|
|
|
|
return lp_result;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|