//============================================================================== // // Copyright (c) 2002- // Authors: // * Dave Parker (University of Oxford) // * Hongyang Qu (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 #include #include #include #include #include #include "sparse.h" #include "PrismSparseGlob.h" #include "jnipointer.h" #include #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; iGetArrayLength(_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; ieoff + 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; inon_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 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 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 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 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 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 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=0; k--) if(arr_reals[k] != 0.0) tail = ec_list(ec_refs_get(Vars, k), tail); for(k=0; k 0) { for(k=0; k 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=0; k--) if(arr_reals[k] != 0.0) tail = ec_list(ec_refs_get(Vars, k), tail); for(k=0; 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 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 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 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 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; k1 || 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 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 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; i1 || cols[l2] != i || non_zeros[l2]!=1.0) { if (maybe_vec[i]> 0 || yes_vec[i]> 0) for(k=l2; 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 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 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; i0) 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 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 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=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; k2) continue; //PS_PrintToMainLog(env, "num_map = %1d, i = %1d, bound = %1.1f\n", num_map, i, bounds[i]); for(k=0; 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="),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 0) { for(j=num_lp_vars; j 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 0 && relops[0]<=2) { //fprintf(f, " optimize(max("); //l2 = 0; for(i=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 if(relops[0] == 0) { //fprintf(f, " optimize(max("); //l2 = 0; for(i=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 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 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; i1) { fprintf(f, " %1d [label=\"\", shape=point]\n", count); fprintf(f, " %1d -> %1d\n", i, count); for(k=l2; k %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 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 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; j1) { // 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 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= 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 %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 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 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; j1) { // 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 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= 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 %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; iReleaseLongArrayElements(_targets, target_ptrs, 0); if (relops) env->ReleaseIntArrayElements(_relops, relops, 0); if (bounds) env->ReleaseDoubleArrayElements(_bounds, bounds, 0); return lp_result; } //------------------------------------------------------------------------------