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.
1320 lines
43 KiB
1320 lines
43 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2002-
|
|
// Authors:
|
|
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford, formerly University of Birmingham)
|
|
// * Rashid Mehmood <rxm@cs.bham.ac.uk> (University of Birmingham)
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// 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
|
|
//
|
|
//==============================================================================
|
|
|
|
#include <cmath>
|
|
#include "dv.h"
|
|
#include "sparse.h"
|
|
#include "PrismSparseGlob.h"
|
|
#include <new>
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// local function prototypes
|
|
|
|
static void split_mdp_rec(DdManager *ddman, DdNode *dd, DdNode **ndvars, int num_ndvars, int level, DdNode **matrices);
|
|
static void split_mdp_and_sub_mdp_rec(DdManager *ddman, DdNode *dd, DdNode *subdd, DdNode **ndvars, int num_ndvars, int level, DdNode **matrices, DdNode **submatrices);
|
|
static void traverse_mtbdd_matr_rec(DdManager *ddman, DdNode *dd, DdNode **rvars, DdNode **cvars, int num_vars, int level, ODDNode *row, ODDNode *col, int r, int c, int code, bool transpose);
|
|
static void traverse_mtbdd_vect_rec(DdManager *ddman, DdNode *dd, DdNode **vars, int num_vars, int level, ODDNode *odd, int i, int code);
|
|
|
|
// global variables (used by local functions)
|
|
static int count;
|
|
static int *starts, *starts2;
|
|
static int *actions;
|
|
static RMSparseMatrix *rmsm;
|
|
static CMSparseMatrix *cmsm;
|
|
static RCSparseMatrix *rcsm;
|
|
static CMSRSparseMatrix *cmsrsm;
|
|
static CMSCSparseMatrix *cmscsm;
|
|
static NDSparseMatrix *ndsm;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Data structure constructors/deconstructors
|
|
//------------------------------------------------------------------------------
|
|
|
|
EXPORT RMSparseMatrix::RMSparseMatrix()
|
|
{
|
|
n = 0;
|
|
nnz = 0;
|
|
use_counts = false;
|
|
mem = 0.0;
|
|
non_zeros = NULL;
|
|
cols = NULL;
|
|
row_counts = NULL;
|
|
}
|
|
|
|
EXPORT RMSparseMatrix::~RMSparseMatrix()
|
|
{
|
|
if (non_zeros) delete[] non_zeros;
|
|
if (cols) delete[] cols;
|
|
if (row_counts) delete[] row_counts;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
EXPORT CMSparseMatrix::CMSparseMatrix()
|
|
{
|
|
n = 0;
|
|
nnz = 0;
|
|
use_counts = false;
|
|
mem = 0.0;
|
|
non_zeros = NULL;
|
|
rows = NULL;
|
|
col_counts = NULL;
|
|
}
|
|
|
|
EXPORT CMSparseMatrix::~CMSparseMatrix()
|
|
{
|
|
if (non_zeros) delete[] non_zeros;
|
|
if (rows) delete[] rows;
|
|
if (col_counts) delete[] col_counts;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
EXPORT RCSparseMatrix::RCSparseMatrix()
|
|
{
|
|
n = 0;
|
|
nnz = 0;
|
|
use_counts = false;
|
|
mem = 0.0;
|
|
non_zeros = NULL;
|
|
rows = NULL;
|
|
cols = NULL;
|
|
}
|
|
|
|
EXPORT RCSparseMatrix::~RCSparseMatrix()
|
|
{
|
|
if (non_zeros) delete[] non_zeros;
|
|
if (rows) delete[] rows;
|
|
if (cols) delete[] cols;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
EXPORT CMSRSparseMatrix::CMSRSparseMatrix()
|
|
{
|
|
n = 0;
|
|
nnz = 0;
|
|
use_counts = false;
|
|
mem = 0.0;
|
|
dist = NULL;
|
|
dist_num = 0;
|
|
dist_shift = 0;
|
|
dist_mask = 0;
|
|
cols = NULL;
|
|
row_counts = NULL;
|
|
}
|
|
|
|
EXPORT CMSRSparseMatrix::~CMSRSparseMatrix()
|
|
{
|
|
if (dist) delete[] dist;
|
|
if (cols) delete[] cols;
|
|
use_counts ? delete[] row_counts : delete[] (int*)row_counts;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
EXPORT CMSCSparseMatrix::CMSCSparseMatrix()
|
|
{
|
|
n = 0;
|
|
nnz = 0;
|
|
use_counts = false;
|
|
mem = 0.0;
|
|
dist = NULL;
|
|
dist_num = 0;
|
|
dist_shift = 0;
|
|
dist_mask = 0;
|
|
rows = NULL;
|
|
col_counts = NULL;
|
|
}
|
|
|
|
EXPORT CMSCSparseMatrix::~CMSCSparseMatrix()
|
|
{
|
|
if (dist) delete[] dist;
|
|
if (rows) delete[] rows;
|
|
use_counts ? delete[] col_counts : delete[] (int*)col_counts;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
EXPORT NDSparseMatrix::NDSparseMatrix()
|
|
{
|
|
n = 0;
|
|
nc = 0;
|
|
nnz = 0;
|
|
k = 0;
|
|
use_counts = false;
|
|
mem = 0.0;
|
|
non_zeros = NULL;
|
|
cols = NULL;
|
|
row_counts = NULL;
|
|
choice_counts = NULL;
|
|
actions = NULL;
|
|
}
|
|
|
|
EXPORT NDSparseMatrix::~NDSparseMatrix()
|
|
{
|
|
if (non_zeros) delete[] non_zeros;
|
|
if (cols) delete[] cols;
|
|
if (row_counts) delete[] row_counts;
|
|
if (choice_counts) delete[] choice_counts;
|
|
if (actions) delete[] actions;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// sparse utility functions
|
|
//------------------------------------------------------------------------------
|
|
|
|
// build row major (rm) sparse matrix
|
|
// if tranpose flag is true, actually construct for tranpose
|
|
// throws std::bad_alloc on out-of-memory
|
|
|
|
RMSparseMatrix *build_rm_sparse_matrix(DdManager *ddman, DdNode *matrix, DdNode **rvars, DdNode **cvars, int num_vars, ODDNode *odd)
|
|
{ return build_rm_sparse_matrix(ddman, matrix, rvars, cvars, num_vars, odd, false); }
|
|
|
|
RMSparseMatrix *build_rm_sparse_matrix(DdManager *ddman, DdNode *matrix, DdNode **rvars, DdNode **cvars, int num_vars, ODDNode *odd, bool transpose)
|
|
{
|
|
int i, n, nnz, max;
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
try {
|
|
|
|
// create new data structure
|
|
rmsm = NULL; rmsm = new RMSparseMatrix();
|
|
|
|
// get number of states from odd
|
|
n = rmsm->n = odd->eoff+odd->toff;
|
|
// get num of transitions
|
|
nnz = rmsm->nnz = (int)DD_GetNumMinterms(ddman, matrix, num_vars*2);
|
|
|
|
// create arrays
|
|
rmsm->non_zeros = new double[nnz];
|
|
rmsm->cols = new unsigned int[nnz];
|
|
starts = NULL; starts = new int[n+1];
|
|
|
|
// first traverse the mtbdd to compute how many entries are in each row
|
|
for (i = 0; i < n+1; i++) starts[i] = 0;
|
|
traverse_mtbdd_matr_rec(ddman, matrix, rvars, cvars, num_vars, 0, odd, odd, 0, 0, 1, transpose);
|
|
// and use this to compute the starts information
|
|
// (and at same time, compute max num entries in a row)
|
|
max = 0;
|
|
for (i = 1; i < n+1; i++) {
|
|
if (starts[i] > max) max = starts[i];
|
|
starts[i] += starts[i-1];
|
|
}
|
|
// max num entries determines whether we store counts or starts:
|
|
rmsm->use_counts = (max < (unsigned int)(1 << (8*sizeof(unsigned char))));
|
|
|
|
// now traverse the mtbdd again to get the actual matrix entries
|
|
traverse_mtbdd_matr_rec(ddman, matrix, rvars, cvars, num_vars, 0, odd, odd, 0, 0, 2, transpose);
|
|
// and recompute starts info because we've messed with it during previous traversal
|
|
for (i = n; i > 0; i--) {
|
|
starts[i] = starts[i-1];
|
|
}
|
|
starts[0] = 0;
|
|
// and if it's safe to do so, replace starts with (smaller) array of counts
|
|
if (rmsm->use_counts) {
|
|
rmsm->row_counts = new unsigned char[n];
|
|
for (i = 0; i < n; i++) rmsm->row_counts[i] = (unsigned char)(starts[i+1] - starts[i]);
|
|
delete[] starts; starts = NULL;
|
|
rmsm->mem = (nnz * (sizeof(double) + sizeof(unsigned int)) + n * sizeof(unsigned char)) / 1024.0;
|
|
} else {
|
|
rmsm->row_counts = (unsigned char*)starts;
|
|
rmsm->mem = (nnz * (sizeof(double) + sizeof(unsigned int)) + n * sizeof(int)) / 1024.0;
|
|
}
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
} catch(std::bad_alloc e) {
|
|
if (rmsm) delete rmsm;
|
|
if (starts) delete[] starts;
|
|
throw e;
|
|
}
|
|
|
|
return rmsm;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// build column major (cm) sparse matrix
|
|
// if tranpose flag is true, actually construct for tranpose
|
|
// throws std::bad_alloc on out-of-memory
|
|
|
|
CMSparseMatrix *build_cm_sparse_matrix(DdManager *ddman, DdNode *matrix, DdNode **rvars, DdNode **cvars, int num_vars, ODDNode *odd)
|
|
{ return build_cm_sparse_matrix(ddman, matrix, rvars, cvars, num_vars, odd, false); }
|
|
|
|
CMSparseMatrix *build_cm_sparse_matrix(DdManager *ddman, DdNode *matrix, DdNode **rvars, DdNode **cvars, int num_vars, ODDNode *odd, bool transpose)
|
|
{
|
|
int i, n, nnz, max;
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
try {
|
|
|
|
// create new data structure
|
|
cmsm = NULL; cmsm = new CMSparseMatrix();
|
|
|
|
// get number of states from odd
|
|
n = cmsm->n = odd->eoff+odd->toff;
|
|
// get num of transitions
|
|
nnz = cmsm->nnz = (int)DD_GetNumMinterms(ddman, matrix, num_vars*2);
|
|
|
|
// create arrays
|
|
cmsm->non_zeros = new double[nnz];
|
|
cmsm->rows = new unsigned int[nnz];
|
|
starts = NULL; starts = new int[n+1];
|
|
|
|
// first traverse the mtbdd to compute how many entries are in each column
|
|
for (i = 0; i < n+1; i++) starts[i] = 0;
|
|
traverse_mtbdd_matr_rec(ddman, matrix, rvars, cvars, num_vars, 0, odd, odd, 0, 0, 3, transpose);
|
|
// and use this to compute the starts information
|
|
// (and at same time, compute max num entries in a column)
|
|
max = 0;
|
|
for (i = 1; i < n+1; i++) {
|
|
if (starts[i] > max) max = starts[i];
|
|
starts[i] += starts[i-1];
|
|
}
|
|
// max num entries determines whether we store counts or starts:
|
|
cmsm->use_counts = (max < (unsigned int)(1 << (8*sizeof(unsigned char))));
|
|
|
|
// now traverse the mtbdd again to get the actual matrix entries
|
|
traverse_mtbdd_matr_rec(ddman, matrix, rvars, cvars, num_vars, 0, odd, odd, 0, 0, 4, transpose);
|
|
// and recompute starts info because we've messed with it during previous traversal
|
|
for (i = n; i > 0; i--) {
|
|
starts[i] = starts[i-1];
|
|
}
|
|
starts[0] = 0;
|
|
// and if it's safe to do so, replace starts with (smaller) array of counts
|
|
if (cmsm->use_counts) {
|
|
cmsm->col_counts = new unsigned char[n];
|
|
for (i = 0; i < n; i++) cmsm->col_counts[i] = (unsigned char)(starts[i+1] - starts[i]);
|
|
delete[] starts; starts = NULL;
|
|
cmsm->mem = (nnz * (sizeof(double) + sizeof(unsigned int)) + n * sizeof(unsigned char)) / 1024.0;
|
|
} else {
|
|
cmsm->col_counts = (unsigned char*)starts;
|
|
cmsm->mem = (nnz * (sizeof(double) + sizeof(unsigned int)) + n * sizeof(int)) / 1024.0;
|
|
}
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
} catch(std::bad_alloc e) {
|
|
if (cmsm) delete cmsm;
|
|
if (starts) delete[] starts;
|
|
throw e;
|
|
}
|
|
|
|
return cmsm;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// build row/column (rc) sparse matrix
|
|
// if tranpose flag is true, actually construct for tranpose
|
|
// throws std::bad_alloc on out-of-memory
|
|
|
|
RCSparseMatrix *build_rc_sparse_matrix(DdManager *ddman, DdNode *matrix, DdNode **rvars, DdNode **cvars, int num_vars, ODDNode *odd)
|
|
{ return build_rc_sparse_matrix(ddman, matrix, rvars, cvars, num_vars, odd, false); }
|
|
|
|
RCSparseMatrix *build_rc_sparse_matrix(DdManager *ddman, DdNode *matrix, DdNode **rvars, DdNode **cvars, int num_vars, ODDNode *odd, bool transpose)
|
|
{
|
|
int n, nnz;
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
try {
|
|
|
|
// create new data structure
|
|
rcsm = NULL; rcsm = new RCSparseMatrix();
|
|
|
|
// get number of states from odd
|
|
n = rcsm->n = odd->eoff+odd->toff;
|
|
// get num of transitions
|
|
nnz = rcsm->nnz = (int)DD_GetNumMinterms(ddman, matrix, num_vars*2);
|
|
|
|
// create arrays
|
|
rcsm->non_zeros = new double[nnz];
|
|
rcsm->rows = new unsigned int[nnz];
|
|
rcsm->cols = new unsigned int[nnz];
|
|
|
|
// traverse the mtbdd to get the matrix entries
|
|
count = 0;
|
|
traverse_mtbdd_matr_rec(ddman, matrix, rvars, cvars, num_vars, 0, odd, odd, 0, 0, 5, transpose);
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
} catch(std::bad_alloc e) {
|
|
if (rcsm) delete rcsm;
|
|
throw e;
|
|
}
|
|
|
|
return rcsm;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// build compact modified sparse row (cmsr) sparse matrix
|
|
// if tranpose flag is true, actually construct for tranpose
|
|
// throws std::bad_alloc on out-of-memory
|
|
|
|
CMSRSparseMatrix *build_cmsr_sparse_matrix(DdManager *ddman, DdNode *matrix, DdNode **rvars, DdNode **cvars, int num_vars, ODDNode *odd)
|
|
{ return build_cmsr_sparse_matrix(ddman, matrix, rvars, cvars, num_vars, odd, false); }
|
|
|
|
CMSRSparseMatrix *build_cmsr_sparse_matrix(DdManager *ddman, DdNode *matrix, DdNode **rvars, DdNode **cvars, int num_vars, ODDNode *odd, bool transpose)
|
|
{
|
|
int i, n, nnz, max, sparebits;
|
|
unsigned int maxsize;
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
try {
|
|
|
|
// create new data structure
|
|
cmsrsm = NULL; cmsrsm = new CMSRSparseMatrix();
|
|
|
|
// get number of states from odd
|
|
n = cmsrsm->n = odd->eoff+odd->toff;
|
|
|
|
// determine number of distinct values
|
|
// and see if compact storage is feasible; if not, abandon it
|
|
cmsrsm->dist_num = DD_GetNumTerminals(ddman, matrix);
|
|
cmsrsm->dist_shift = (int)ceil(logtwo(cmsrsm->dist_num));
|
|
if (cmsrsm->dist_shift == 0) cmsrsm->dist_shift++;
|
|
// this is how many bits are free to store row/column indices
|
|
sparebits = 8*sizeof(unsigned int) - cmsrsm->dist_shift;
|
|
if (sparebits == 8*sizeof(unsigned int)) sparebits--;
|
|
// so this is the max size of sparse matrix we can afford
|
|
maxsize = 1 << sparebits;
|
|
if (n > maxsize) {
|
|
delete cmsrsm;
|
|
return NULL;
|
|
}
|
|
|
|
// compute mask, allocate array for distinct vals
|
|
cmsrsm->dist_mask = (1 << cmsrsm->dist_shift) - 1;
|
|
cmsrsm->dist = new double[cmsrsm->dist_num];
|
|
// reset total to zero because we haven't actually stored any values yet
|
|
cmsrsm->dist_num = 0;
|
|
|
|
// get num of transitions
|
|
nnz = cmsrsm->nnz = (int)DD_GetNumMinterms(ddman, matrix, num_vars*2);
|
|
|
|
// allocate temporary array to store start of each row
|
|
starts = NULL; starts = new int[n+1];
|
|
|
|
// first traverse the mtbdd to compute how many entries are in each row
|
|
for (i = 0; i < n+1; i++) starts[i] = 0;
|
|
traverse_mtbdd_matr_rec(ddman, matrix, rvars, cvars, num_vars, 0, odd, odd, 0, 0, 6, transpose);
|
|
// and use this to compute the starts information
|
|
// (and at same time, compute max num entries in a row)
|
|
max = 0;
|
|
for (i = 1; i < n+1; i++) {
|
|
if (starts[i] > max) max = starts[i];
|
|
starts[i] += starts[i-1];
|
|
}
|
|
// max num entries determines whether we store counts or starts:
|
|
cmsrsm->use_counts = (max < (unsigned int)(1 << (8*sizeof(unsigned char))));
|
|
|
|
// allocate other array
|
|
cmsrsm->cols = new unsigned int[nnz];
|
|
|
|
// now traverse the mtbdd again to get the actual matrix entries
|
|
traverse_mtbdd_matr_rec(ddman, matrix, rvars, cvars, num_vars, 0, odd, odd, 0, 0, 7, transpose);
|
|
// and recompute starts info because we've messed with it during previous traversal
|
|
for (i = n; i > 0; i--) {
|
|
starts[i] = starts[i-1];
|
|
}
|
|
starts[0] = 0;
|
|
// and if it's safe to do so, replace starts with (smaller) array of counts
|
|
if (cmsrsm->use_counts) {
|
|
cmsrsm->row_counts = new unsigned char[n];
|
|
for (i = 0; i < n; i++) cmsrsm->row_counts[i] = (unsigned char)(starts[i+1] - starts[i]);
|
|
delete[] starts; starts = NULL;
|
|
cmsrsm->mem = (cmsrsm->dist_num * sizeof(double) + nnz * sizeof(unsigned int) + n * sizeof(unsigned char)) / 1024.0;
|
|
} else {
|
|
cmsrsm->row_counts = (unsigned char*)starts;
|
|
cmsrsm->mem = (cmsrsm->dist_num * sizeof(double) + nnz * sizeof(unsigned int) + n * sizeof(int)) / 1024.0;
|
|
}
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
} catch(std::bad_alloc e) {
|
|
if (cmsrsm) delete cmsrsm;
|
|
if (starts) delete[] starts;
|
|
throw e;
|
|
}
|
|
|
|
return cmsrsm;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// build compact modified sparse column (cmsc) sparse matrix
|
|
// if tranpose flag is true, actually construct for tranpose
|
|
// throws std::bad_alloc on out-of-memory
|
|
|
|
CMSCSparseMatrix *build_cmsc_sparse_matrix(DdManager *ddman, DdNode *matrix, DdNode **rvars, DdNode **cvars, int num_vars, ODDNode *odd)
|
|
{ return build_cmsc_sparse_matrix(ddman, matrix, rvars, cvars, num_vars, odd, false); }
|
|
|
|
CMSCSparseMatrix *build_cmsc_sparse_matrix(DdManager *ddman, DdNode *matrix, DdNode **rvars, DdNode **cvars, int num_vars, ODDNode *odd, bool transpose)
|
|
{
|
|
int i, n, nnz, max, sparebits;
|
|
unsigned int maxsize;
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
try {
|
|
|
|
// create new data structure
|
|
cmscsm = NULL; cmscsm = new CMSCSparseMatrix();
|
|
|
|
// get number of states from odd
|
|
n = cmscsm->n = odd->eoff+odd->toff;
|
|
|
|
// determine number of distinct values
|
|
// and see if compact storage is feasible; if not, abandon it
|
|
cmscsm->dist_num = DD_GetNumTerminals(ddman, matrix);
|
|
cmscsm->dist_shift = (int)ceil(logtwo(cmscsm->dist_num));
|
|
if (cmscsm->dist_shift == 0) cmscsm->dist_shift++;
|
|
// this is how many bits are free to store row/column indices
|
|
sparebits = 8*sizeof(unsigned int) - cmscsm->dist_shift;
|
|
if (sparebits == 8*sizeof(unsigned int)) sparebits--;
|
|
// so this is the max size of sparse matrix we can afford
|
|
maxsize = 1 << sparebits;
|
|
if (n > maxsize) {
|
|
delete cmscsm;
|
|
return NULL;
|
|
}
|
|
|
|
// compute mask, allocate array for distinct vals
|
|
cmscsm->dist_mask = (1 << cmscsm->dist_shift) - 1;
|
|
cmscsm->dist = new double[cmscsm->dist_num];
|
|
// reset total to zero because we haven't actually stored any values yet
|
|
cmscsm->dist_num = 0;
|
|
|
|
// get num of transitions
|
|
nnz = cmscsm->nnz = (int)DD_GetNumMinterms(ddman, matrix, num_vars*2);
|
|
|
|
// allocate temporary array to store start of each row
|
|
starts = NULL; starts = new int[n+1];
|
|
|
|
// first traverse the mtbdd to compute how many entries are in each column
|
|
for (i = 0; i < n+1; i++) starts[i] = 0;
|
|
traverse_mtbdd_matr_rec(ddman, matrix, rvars, cvars, num_vars, 0, odd, odd, 0, 0, 8, transpose);
|
|
// and use this to compute the starts information
|
|
// (and at same time, compute max num entries in a column)
|
|
max = 0;
|
|
for (i = 1; i < n+1; i++) {
|
|
if (starts[i] > max) max = starts[i];
|
|
starts[i] += starts[i-1];
|
|
}
|
|
// max num entries determines whether we store counts or starts:
|
|
cmscsm->use_counts = (max < (unsigned int)(1 << (8*sizeof(unsigned char))));
|
|
|
|
// allocate other array
|
|
cmscsm->rows = new unsigned int[nnz];
|
|
|
|
// now traverse the mtbdd again to get the actual matrix entries
|
|
traverse_mtbdd_matr_rec(ddman, matrix, rvars, cvars, num_vars, 0, odd, odd, 0, 0, 9, transpose);
|
|
// and recompute starts info because we've messed with it during previous traversal
|
|
for (i = n; i > 0; i--) {
|
|
starts[i] = starts[i-1];
|
|
}
|
|
starts[0] = 0;
|
|
// and if it's safe to do so, replace starts with (smaller) array of counts
|
|
if (cmscsm->use_counts) {
|
|
cmscsm->col_counts = new unsigned char[n];
|
|
for (i = 0; i < n; i++) cmscsm->col_counts[i] = (unsigned char)(starts[i+1] - starts[i]);
|
|
delete[] starts; starts = NULL;
|
|
cmscsm->mem = (cmscsm->dist_num * sizeof(double) + nnz * sizeof(unsigned int) + n * sizeof(unsigned char)) / 1024.0;
|
|
} else {
|
|
cmscsm->col_counts = (unsigned char*)starts;
|
|
cmscsm->mem = (cmscsm->dist_num * sizeof(double) + nnz * sizeof(unsigned int) + n * sizeof(int)) / 1024.0;
|
|
}
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
} catch(std::bad_alloc e) {
|
|
if (cmscsm) delete cmscsm;
|
|
if (starts) delete[] starts;
|
|
throw e;
|
|
}
|
|
|
|
return cmscsm;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
// build nondeterministic (mdp) sparse matrix
|
|
// throws std::bad_alloc on out-of-memory
|
|
|
|
NDSparseMatrix *build_nd_sparse_matrix(DdManager *ddman, DdNode *mdp, DdNode **rvars, DdNode **cvars, int num_vars, DdNode **ndvars, int num_ndvars, ODDNode *odd)
|
|
{
|
|
int i, n, nm, nc, nnz, max, max2;
|
|
DdNode *tmp = NULL, **matrices = NULL, **matrices_bdds = NULL;
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
try {
|
|
|
|
// create new data structure
|
|
ndsm = NULL; ndsm = new NDSparseMatrix();
|
|
|
|
// get number of states from odd
|
|
n = ndsm->n = odd->eoff+odd->toff;
|
|
// get num of choices (prob. distributions)
|
|
Cudd_Ref(mdp);
|
|
tmp = DD_ThereExists(ddman, DD_Not(ddman, DD_Equals(ddman, mdp, 0)), cvars, num_vars);
|
|
nc = ndsm->nc = (int)DD_GetNumMinterms(ddman, tmp, num_vars+num_ndvars);
|
|
// get num of transitions
|
|
nnz = ndsm->nnz = (int)DD_GetNumMinterms(ddman, mdp, num_vars*2+num_ndvars);
|
|
// break the mdp mtbdd into several (nm) mtbdds
|
|
tmp = DD_ThereExists(ddman, tmp, rvars, num_vars);
|
|
nm = (int)DD_GetNumMinterms(ddman, tmp, num_ndvars);
|
|
Cudd_RecursiveDeref(ddman, tmp);
|
|
matrices = new DdNode*[nm];
|
|
count = 0;
|
|
split_mdp_rec(ddman, mdp, ndvars, num_ndvars, 0, matrices);
|
|
// and for each one create a bdd storing which rows/choices are non-empty
|
|
matrices_bdds = new DdNode*[nm];
|
|
for (i = 0; i < nm; i++) {
|
|
Cudd_Ref(matrices[i]);
|
|
matrices_bdds[i] = DD_ThereExists(ddman, DD_Not(ddman, DD_Equals(ddman, matrices[i], 0)), cvars, num_vars);
|
|
}
|
|
|
|
// create arrays
|
|
ndsm->non_zeros = new double[nnz];
|
|
ndsm->cols = new unsigned int[nnz];
|
|
starts = NULL; starts = new int[n+1];
|
|
starts2 = NULL; starts2 = new int[nc+1];
|
|
|
|
// first traverse mtbdds to compute how many choices are in each row
|
|
for (i = 0; i < n+1; i++) starts[i] = 0;
|
|
for (i = 0; i < nm; i++) {
|
|
traverse_mtbdd_vect_rec(ddman, matrices_bdds[i], rvars, num_vars, 0, odd, 0, 1);
|
|
}
|
|
// and use this to compute the starts information
|
|
// (and at same time, compute max num choices in a state)
|
|
max = 0;
|
|
for (i = 1 ; i < n+1; i++) {
|
|
if (starts[i] > max) max = starts[i];
|
|
starts[i] += starts[i-1];
|
|
}
|
|
ndsm->k = max;
|
|
|
|
// now traverse mtbdds to compute how many transitions in each choice
|
|
for (i = 0; i < nc+1; i++) starts2[i] = 0;
|
|
for (i = 0; i < nm; i++) {
|
|
traverse_mtbdd_matr_rec(ddman, matrices[i], rvars, cvars, num_vars, 0, odd, odd, 0, 0, 10, false);
|
|
traverse_mtbdd_vect_rec(ddman, matrices_bdds[i], rvars, num_vars, 0, odd, 0, 2);
|
|
}
|
|
// and use this to compute the starts2 information
|
|
// (and at same time, compute max num transitions in a choice)
|
|
max2 = 0;
|
|
for (i = 1; i < nc+1; i++) {
|
|
if (starts2[i] > max2) max2 = starts2[i];
|
|
starts2[i] += starts2[i-1];
|
|
}
|
|
// recompute starts (because we altered them during last traversal)
|
|
for (i = n; i > 0; i--) {
|
|
starts[i] = starts[i-1];
|
|
}
|
|
starts[0] = 0;
|
|
|
|
// max num choices/transitions determines whether we store counts or starts:
|
|
ndsm->use_counts = (max < (unsigned int)(1 << (8*sizeof(unsigned char))));
|
|
ndsm->use_counts &= (max2 < (unsigned int)(1 << (8*sizeof(unsigned char))));
|
|
|
|
// now traverse the mtbdd again to get the actual matrix entries
|
|
for (i = 0; i < nm; i++) {
|
|
traverse_mtbdd_matr_rec(ddman, matrices[i], rvars, cvars, num_vars, 0, odd, odd, 0, 0, 11, false);
|
|
traverse_mtbdd_vect_rec(ddman, matrices_bdds[i], rvars, num_vars, 0, odd, 0, 2);
|
|
}
|
|
// recompute starts (because we altered them during last traversal)
|
|
for (i = n; i > 0; i--) {
|
|
starts[i] = starts[i-1];
|
|
}
|
|
starts[0] = 0;
|
|
// recompute starts2 (likewise)
|
|
for (i = nc; i > 0; i--) {
|
|
starts2[i] = starts2[i-1];
|
|
}
|
|
starts2[0] = 0;
|
|
|
|
// if it's safe to do so, replace starts/starts2 with (smaller) arrays of counts
|
|
if (ndsm->use_counts) {
|
|
ndsm->row_counts = new unsigned char[n];
|
|
for (i = 0; i < n; i++) ndsm->row_counts[i] = (unsigned char)(starts[i+1] - starts[i]);
|
|
delete[] starts; starts = NULL;
|
|
ndsm->choice_counts = new unsigned char[nc];
|
|
for (i = 0; i < nc; i++) ndsm->choice_counts[i] = (unsigned char)(starts2[i+1] - starts2[i]);
|
|
delete[] starts2; starts2 = NULL;
|
|
ndsm->mem = (nnz * (sizeof(double) + sizeof(unsigned int)) + (n+nc) * sizeof(unsigned char)) / 1024.0;
|
|
} else {
|
|
ndsm->row_counts = (unsigned char*)starts;
|
|
ndsm->choice_counts = (unsigned char*)starts2;
|
|
ndsm->mem = (nnz * (sizeof(double) + sizeof(unsigned int)) + (n+nc) * sizeof(int)) / 1024.0;
|
|
}
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
} catch(std::bad_alloc e) {
|
|
if (ndsm) delete ndsm;
|
|
if (matrices) delete[] matrices;
|
|
if (matrices_bdds) {
|
|
for (i = 0; i < nm; i++) Cudd_RecursiveDeref(ddman, matrices_bdds[i]);
|
|
delete[] matrices_bdds;
|
|
}
|
|
if (starts) delete[] starts;
|
|
if (starts2) delete[] starts2;
|
|
throw e;
|
|
}
|
|
|
|
// clear up memory
|
|
for (i = 0; i < nm; i++) {
|
|
Cudd_RecursiveDeref(ddman, matrices_bdds[i]);
|
|
// nb: don't deref matrices array because that was just pointers, not new copies
|
|
}
|
|
delete[] matrices;
|
|
delete[] matrices_bdds;
|
|
|
|
return ndsm;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
// Build nondeterministic (MDP) sparse matrix for "sub-MDP".
|
|
// This function basically exists to construct a sparse matrix representing the transition rewards for an MDP.
|
|
// The complication is that we need to use the nondeterministic choice indexing of the main
|
|
// MDP matrix, not the rewards matrix, otherwise we can't tell which reward is on which transition.
|
|
// throws std::bad_alloc on out-of-memory
|
|
|
|
NDSparseMatrix *build_sub_nd_sparse_matrix(DdManager *ddman, DdNode *mdp, DdNode *submdp, DdNode **rvars, DdNode **cvars, int num_vars, DdNode **ndvars, int num_ndvars, ODDNode *odd)
|
|
{
|
|
int i, n, nm, nc, nnz, max, max2;
|
|
DdNode *tmp = NULL, **matrices = NULL, **submatrices = NULL, **matrices_bdds = NULL;
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
try {
|
|
|
|
// create new data structure
|
|
ndsm = NULL; ndsm = new NDSparseMatrix();
|
|
|
|
// get number of states from odd
|
|
n = ndsm->n = odd->eoff+odd->toff;
|
|
// get num of choices (prob. distributions) (USING MDP)
|
|
Cudd_Ref(mdp);
|
|
tmp = DD_ThereExists(ddman, DD_Not(ddman, DD_Equals(ddman, mdp, 0)), cvars, num_vars);
|
|
nc = ndsm->nc = (int)DD_GetNumMinterms(ddman, tmp, num_vars+num_ndvars);
|
|
// get num of transitions (USING SUB-MDP)
|
|
nnz = ndsm->nnz = (int)DD_GetNumMinterms(ddman, submdp, num_vars*2+num_ndvars);
|
|
// break the two mtbdds (MDP AND SUB-MDP) into several (nm) mtbdds
|
|
tmp = DD_ThereExists(ddman, tmp, rvars, num_vars);
|
|
nm = (int)DD_GetNumMinterms(ddman, tmp, num_ndvars);
|
|
Cudd_RecursiveDeref(ddman, tmp);
|
|
matrices = new DdNode*[nm];
|
|
submatrices = new DdNode*[nm];
|
|
count = 0;
|
|
split_mdp_and_sub_mdp_rec(ddman, mdp, submdp, ndvars, num_ndvars, 0, matrices, submatrices);
|
|
// and for each one create a bdd storing which rows/choices are non-empty (USING MDP)
|
|
matrices_bdds = new DdNode*[nm];
|
|
for (i = 0; i < nm; i++) {
|
|
Cudd_Ref(matrices[i]);
|
|
matrices_bdds[i] = DD_ThereExists(ddman, DD_Not(ddman, DD_Equals(ddman, matrices[i], 0)), cvars, num_vars);
|
|
}
|
|
|
|
// create arrays
|
|
ndsm->non_zeros = new double[nnz];
|
|
ndsm->cols = new unsigned int[nnz];
|
|
starts = NULL; starts = new int[n+1];
|
|
starts2 = NULL; starts2 = new int[nc+1];
|
|
|
|
// first traverse mtbdds to compute how many choices are in each row (USING MDP)
|
|
for (i = 0; i < n+1; i++) starts[i] = 0;
|
|
for (i = 0; i < nm; i++) {
|
|
traverse_mtbdd_vect_rec(ddman, matrices_bdds[i], rvars, num_vars, 0, odd, 0, 1);
|
|
}
|
|
// and use this to compute the starts information
|
|
// (and at same time, compute max num choices in a state)
|
|
max = 0;
|
|
for (i = 1 ; i < n+1; i++) {
|
|
if (starts[i] > max) max = starts[i];
|
|
starts[i] += starts[i-1];
|
|
}
|
|
ndsm->k = max;
|
|
|
|
// now traverse mtbdds to compute how many transitions in each choice (USING SUB-MDP)
|
|
for (i = 0; i < nc+1; i++) starts2[i] = 0;
|
|
for (i = 0; i < nm; i++) {
|
|
traverse_mtbdd_matr_rec(ddman, submatrices[i], rvars, cvars, num_vars, 0, odd, odd, 0, 0, 10, false);
|
|
traverse_mtbdd_vect_rec(ddman, matrices_bdds[i], rvars, num_vars, 0, odd, 0, 2);
|
|
}
|
|
// and use this to compute the starts2 information
|
|
// (and at same time, compute max num transitions in a choice)
|
|
max2 = 0;
|
|
for (i = 1; i < nc+1; i++) {
|
|
if (starts2[i] > max2) max2 = starts2[i];
|
|
starts2[i] += starts2[i-1];
|
|
}
|
|
// recompute starts (because we altered them during last traversal)
|
|
for (i = n; i > 0; i--) {
|
|
starts[i] = starts[i-1];
|
|
}
|
|
starts[0] = 0;
|
|
|
|
// max num choices/transitions determines whether we store counts or starts:
|
|
ndsm->use_counts = (max < (unsigned int)(1 << (8*sizeof(unsigned char))));
|
|
ndsm->use_counts &= (max2 < (unsigned int)(1 << (8*sizeof(unsigned char))));
|
|
|
|
// now traverse the mtbdd again to get the actual matrix entries (USING SUB-MDP)
|
|
for (i = 0; i < nm; i++) {
|
|
traverse_mtbdd_matr_rec(ddman, submatrices[i], rvars, cvars, num_vars, 0, odd, odd, 0, 0, 11, false);
|
|
traverse_mtbdd_vect_rec(ddman, matrices_bdds[i], rvars, num_vars, 0, odd, 0, 2);
|
|
}
|
|
// recompute starts (because we altered them during last traversal)
|
|
for (i = n; i > 0; i--) {
|
|
starts[i] = starts[i-1];
|
|
}
|
|
starts[0] = 0;
|
|
// recompute starts2 (likewise)
|
|
for (i = nc; i > 0; i--) {
|
|
starts2[i] = starts2[i-1];
|
|
}
|
|
starts2[0] = 0;
|
|
|
|
// if it's safe to do so, replace starts/starts2 with (smaller) arrays of counts
|
|
if (ndsm->use_counts) {
|
|
ndsm->row_counts = new unsigned char[n];
|
|
for (i = 0; i < n; i++) ndsm->row_counts[i] = (unsigned char)(starts[i+1] - starts[i]);
|
|
delete[] starts; starts = NULL;
|
|
ndsm->choice_counts = new unsigned char[nc];
|
|
for (i = 0; i < nc; i++) ndsm->choice_counts[i] = (unsigned char)(starts2[i+1] - starts2[i]);
|
|
delete[] starts2; starts2 = NULL;
|
|
ndsm->mem = (nnz * (sizeof(double) + sizeof(unsigned int)) + (n+nc) * sizeof(unsigned char)) / 1024.0;
|
|
} else {
|
|
ndsm->row_counts = (unsigned char*)starts;
|
|
ndsm->choice_counts = (unsigned char*)starts2;
|
|
ndsm->mem = (nnz * (sizeof(double) + sizeof(unsigned int)) + (n+nc) * sizeof(int)) / 1024.0;
|
|
}
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
} catch(std::bad_alloc e) {
|
|
if (ndsm) delete ndsm;
|
|
if (matrices) delete[] matrices;
|
|
if (submatrices) delete[] submatrices;
|
|
if (matrices_bdds) {
|
|
for (i = 0; i < nm; i++) Cudd_RecursiveDeref(ddman, matrices_bdds[i]);
|
|
delete[] matrices_bdds;
|
|
}
|
|
if (starts) delete[] starts;
|
|
if (starts2) delete[] starts2;
|
|
throw e;
|
|
}
|
|
|
|
// clear up memory
|
|
for (i = 0; i < nm; i++) {
|
|
Cudd_RecursiveDeref(ddman, matrices_bdds[i]);
|
|
// nb: don't deref matrices/submatrices array because that was just pointers, not new copies
|
|
}
|
|
delete[] matrices;
|
|
delete[] submatrices;
|
|
delete[] matrices_bdds;
|
|
|
|
return ndsm;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Build nondeterministic (mdp) action vector to accompany a sparse matrix
|
|
// (i.e. a vector containing for every state and nondet choice, an index
|
|
// into the list of all action labels).
|
|
// Store the resulting vector in the 'actions' member of the passed in NDSparseMatrix.
|
|
// throws std::bad_alloc on out-of-memory
|
|
void build_nd_action_vector(DdManager *ddman, DdNode *mdp, DdNode *trans_actions, NDSparseMatrix *mdp_ndsm, DdNode **rvars, DdNode **cvars, int num_vars, DdNode **ndvars, int num_ndvars, ODDNode *odd)
|
|
{
|
|
int i, n, nm, nc;
|
|
DdNode *tmp = NULL, **matrices = NULL, **submatrices = NULL, **matrices_bdds = NULL;
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
try {
|
|
|
|
// get stats from mdp sparse storage (num states/choices)
|
|
n = mdp_ndsm->n;
|
|
nc = mdp_ndsm->nc;
|
|
// break the mtbdd storing the action info into several (nm) mtbdds
|
|
// like for build_sub_nd_sparse_matrix above, we have to simultaneously traverse and
|
|
// split the mtbdd for the mdp itself - this to make sure that all our indices match up
|
|
// (more precisely, things go wrong where mtbdd storing the action info has a zero - meaning
|
|
// there is no action label - where there is a non-zero probability in the mdp)
|
|
Cudd_Ref(mdp);
|
|
tmp = DD_ThereExists(ddman, DD_Not(ddman, DD_Equals(ddman, mdp, 0)), cvars, num_vars);
|
|
tmp = DD_ThereExists(ddman, tmp, rvars, num_vars);
|
|
nm = (int)DD_GetNumMinterms(ddman, tmp, num_ndvars);
|
|
Cudd_RecursiveDeref(ddman, tmp);
|
|
matrices = new DdNode*[nm];
|
|
submatrices = new DdNode*[nm];
|
|
count = 0;
|
|
split_mdp_and_sub_mdp_rec(ddman, mdp, trans_actions, ndvars, num_ndvars, 0, matrices, submatrices);
|
|
// and for each one create a bdd storing which rows are non-empty
|
|
matrices_bdds = new DdNode*[nm];
|
|
for (i = 0; i < nm; i++) {
|
|
Cudd_Ref(matrices[i]);
|
|
matrices_bdds[i] = DD_ThereExists(ddman, DD_Not(ddman, DD_Equals(ddman, matrices[i], 0)), cvars, num_vars);
|
|
}
|
|
|
|
// create arrays
|
|
actions = NULL; actions = new int[nc];
|
|
starts = NULL; starts = new int[n+1];
|
|
|
|
// build the (temporary) array 'starts' (like was done when building the sparse matrix for the mdp).
|
|
// in fact, this information is retrievable from the sparse matrix, but it may have
|
|
// been converted to counts, rather than offsets, so its easier to rebuild it.
|
|
// first traverse mtbdds to compute how many choices are in each row
|
|
for (i = 0; i < n+1; i++) starts[i] = 0;
|
|
for (i = 0; i < nm; i++) {
|
|
traverse_mtbdd_vect_rec(ddman, matrices_bdds[i], rvars, num_vars, 0, odd, 0, 1);
|
|
}
|
|
// and use this to compute the starts information
|
|
for (i = 1 ; i < n+1; i++) {
|
|
starts[i] += starts[i-1];
|
|
}
|
|
|
|
// initialise the 'actions' array
|
|
// (necessary because tau actions, with index 0, are not discovered
|
|
// by the call to traverse_mtbdd_vect_rec(..., 3) below)
|
|
for (i = 0; i < nc; i++) actions[i] = 0;
|
|
// now traverse the mtbdd to get the actual entries (action indices)
|
|
for (i = 0; i < nm; i++) {
|
|
traverse_mtbdd_vect_rec(ddman, submatrices[i], rvars, num_vars, 0, odd, 0, 3);
|
|
traverse_mtbdd_vect_rec(ddman, matrices_bdds[i], rvars, num_vars, 0, odd, 0, 2);
|
|
}
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
} catch(std::bad_alloc e) {
|
|
if (actions) delete[] actions;
|
|
if (matrices) delete[] matrices;
|
|
if (submatrices) delete[] submatrices;
|
|
if (matrices_bdds) {
|
|
for (i = 0; i < nm; i++) Cudd_RecursiveDeref(ddman, matrices_bdds[i]);
|
|
delete[] matrices_bdds;
|
|
}
|
|
if (starts) delete[] starts;
|
|
throw e;
|
|
}
|
|
|
|
// clear up memory
|
|
for (i = 0; i < nm; i++) {
|
|
Cudd_RecursiveDeref(ddman, matrices_bdds[i]);
|
|
// nb: don't deref matrices/submatrices array because that was just pointers, not new copies
|
|
}
|
|
delete[] starts;
|
|
delete[] matrices;
|
|
delete[] submatrices;
|
|
delete[] matrices_bdds;
|
|
|
|
mdp_ndsm->actions = actions;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void split_mdp_rec(DdManager *ddman, DdNode *dd, DdNode **ndvars, int num_ndvars, int level, DdNode **matrices)
|
|
{
|
|
DdNode *e, *t;
|
|
|
|
// base case - empty matrix
|
|
if (dd == Cudd_ReadZero(ddman)) return;
|
|
|
|
// base case - nonempty matrix
|
|
if (level == num_ndvars) {
|
|
matrices[count++] = dd;
|
|
return;
|
|
}
|
|
|
|
// recurse
|
|
if (dd->index > ndvars[level]->index) {
|
|
e = t = dd;
|
|
}
|
|
else {
|
|
e = Cudd_E(dd);
|
|
t = Cudd_T(dd);
|
|
}
|
|
|
|
split_mdp_rec(ddman, e, ndvars, num_ndvars, level+1, matrices);
|
|
split_mdp_rec(ddman, t, ndvars, num_ndvars, level+1, matrices);
|
|
}
|
|
|
|
void split_mdp_and_sub_mdp_rec(DdManager *ddman, DdNode *dd, DdNode *subdd, DdNode **ndvars, int num_ndvars, int level, DdNode **matrices, DdNode **submatrices)
|
|
{
|
|
DdNode *e, *t, *e2, *t2;
|
|
|
|
// base case - empty matrix
|
|
if (dd == Cudd_ReadZero(ddman)) return;
|
|
|
|
// base case - nonempty matrix
|
|
if (level == num_ndvars) {
|
|
matrices[count] = dd;
|
|
submatrices[count] = subdd;
|
|
count++;
|
|
return;
|
|
}
|
|
|
|
// recurse
|
|
if (dd->index > ndvars[level]->index) {
|
|
e = t = dd;
|
|
}
|
|
else {
|
|
e = Cudd_E(dd);
|
|
t = Cudd_T(dd);
|
|
}
|
|
if (subdd->index > ndvars[level]->index) {
|
|
e2 = t2 = subdd;
|
|
}
|
|
else {
|
|
e2 = Cudd_E(subdd);
|
|
t2 = Cudd_T(subdd);
|
|
}
|
|
|
|
split_mdp_and_sub_mdp_rec(ddman, e, e2, ndvars, num_ndvars, level+1, matrices, submatrices);
|
|
split_mdp_and_sub_mdp_rec(ddman, t, t2, ndvars, num_ndvars, level+1, matrices, submatrices);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// traverses the mtbdd and gets all the MATRIX entries out
|
|
// does different things depending on the value of 'code'
|
|
// if tranpose flag is true, actually extract from tranpose of matrix
|
|
|
|
void traverse_mtbdd_matr_rec(DdManager *ddman, DdNode *dd, DdNode **rvars, DdNode **cvars, int num_vars, int level, ODDNode *row, ODDNode *col, int r, int c, int code, bool transpose)
|
|
{
|
|
DdNode *e, *t, *ee, *et, *te, *tt;
|
|
int i, dist_num;
|
|
double *dist, d;
|
|
|
|
// base case - zero terminal
|
|
if (dd == Cudd_ReadZero(ddman)) return;
|
|
|
|
// base case - non zero terminal
|
|
if (level == num_vars) {
|
|
switch (code) {
|
|
|
|
// row major - first pass
|
|
case 1:
|
|
starts[(transpose?c:r)+1]++;
|
|
break;
|
|
|
|
// row major - second pass
|
|
case 2:
|
|
rmsm->non_zeros[starts[(transpose?c:r)]] = Cudd_V(dd);
|
|
rmsm->cols[starts[(transpose?c:r)]] = (transpose?r:c);
|
|
starts[(transpose?c:r)]++;
|
|
break;
|
|
|
|
// column major - first pass
|
|
case 3:
|
|
starts[(transpose?r:c)+1]++;
|
|
break;
|
|
|
|
// column major - second pass
|
|
case 4:
|
|
cmsm->non_zeros[starts[(transpose?r:c)]] = Cudd_V(dd);
|
|
cmsm->rows[starts[(transpose?r:c)]] = (transpose?c:r);
|
|
starts[(transpose?r:c)]++;
|
|
break;
|
|
|
|
// row/column - only pass
|
|
case 5:
|
|
rcsm->non_zeros[count] = Cudd_V(dd);
|
|
rcsm->rows[count] = (transpose?c:r);
|
|
rcsm->cols[count] = (transpose?r:c);
|
|
count++;
|
|
break;
|
|
|
|
// compact modified sparse row - first pass
|
|
case 6:
|
|
starts[(transpose?c:r)+1]++;
|
|
break;
|
|
|
|
// compact modified sparse row - second pass
|
|
case 7:
|
|
// try and find value
|
|
dist = cmsrsm->dist;
|
|
dist_num = cmsrsm->dist_num;
|
|
d = Cudd_V(dd);
|
|
for (i = 0; i < dist_num; i++) if (dist[i] == d) break;
|
|
// if it's not there, add it
|
|
if (i == dist_num) {
|
|
dist[i] = d;
|
|
cmsrsm->dist_num++;
|
|
}
|
|
// store info
|
|
cmsrsm->cols[starts[(transpose?c:r)]] = (unsigned int)(((unsigned int)(transpose?r:c) << cmsrsm->dist_shift) + (unsigned int)i);
|
|
starts[(transpose?c:r)]++;
|
|
break;
|
|
|
|
// compact modified sparse column - first pass
|
|
case 8:
|
|
starts[(transpose?r:c)+1]++;
|
|
break;
|
|
|
|
// compact modified sparse column - second pass
|
|
case 9:
|
|
// try and find value
|
|
dist = cmscsm->dist;
|
|
dist_num = cmscsm->dist_num;
|
|
d = Cudd_V(dd);
|
|
for (i = 0; i < dist_num; i++) if (dist[i] == d) break;
|
|
// if it's not there, add it
|
|
if (i == dist_num) {
|
|
dist[i] = d;
|
|
cmscsm->dist_num++;
|
|
}
|
|
// store info
|
|
cmscsm->rows[starts[(transpose?r:c)]] = (unsigned int)(((unsigned int)(transpose?c:r) << cmscsm->dist_shift) + (unsigned int)i);
|
|
starts[(transpose?r:c)]++;
|
|
break;
|
|
|
|
// mdp - first pass
|
|
case 10:
|
|
starts2[starts[(transpose?c:r)]+1]++;
|
|
break;
|
|
|
|
// mdp - second pass
|
|
case 11:
|
|
ndsm->non_zeros[starts2[starts[(transpose?c:r)]]] = Cudd_V(dd);
|
|
ndsm->cols[starts2[starts[(transpose?c:r)]]] = (transpose?r:c);
|
|
starts2[starts[(transpose?c:r)]]++;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// recurse
|
|
if (dd->index > cvars[level]->index) {
|
|
ee = et = te = tt = dd;
|
|
}
|
|
else if (dd->index > rvars[level]->index) {
|
|
ee = te = Cudd_E(dd);
|
|
et = tt = Cudd_T(dd);
|
|
}
|
|
else {
|
|
e = Cudd_E(dd);
|
|
if (e->index > cvars[level]->index) {
|
|
ee = et = e;
|
|
}
|
|
else {
|
|
ee = Cudd_E(e);
|
|
et = Cudd_T(e);
|
|
}
|
|
t = Cudd_T(dd);
|
|
if (t->index > cvars[level]->index) {
|
|
te = tt = t;
|
|
}
|
|
else {
|
|
te = Cudd_E(t);
|
|
tt = Cudd_T(t);
|
|
}
|
|
}
|
|
|
|
traverse_mtbdd_matr_rec(ddman, ee, rvars, cvars, num_vars, level+1, row->e, col->e, r, c, code, transpose);
|
|
traverse_mtbdd_matr_rec(ddman, et, rvars, cvars, num_vars, level+1, row->e, col->t, r, c+col->eoff, code, transpose);
|
|
traverse_mtbdd_matr_rec(ddman, te, rvars, cvars, num_vars, level+1, row->t, col->e, r+row->eoff, c, code, transpose);
|
|
traverse_mtbdd_matr_rec(ddman, tt, rvars, cvars, num_vars, level+1, row->t, col->t, r+row->eoff, c+col->eoff, code, transpose);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// traverses the mtbdd and gets all the VECTOR entries out
|
|
// does different things depending on the value of 'code'
|
|
|
|
void traverse_mtbdd_vect_rec(DdManager *ddman, DdNode *dd, DdNode **vars, int num_vars, int level, ODDNode *odd, int i, int code)
|
|
{
|
|
DdNode *e, *t;
|
|
|
|
// base case - zero terminal
|
|
if (dd == Cudd_ReadZero(ddman)) return;
|
|
|
|
// base case - non zero terminal
|
|
if (level == num_vars) {
|
|
switch (code) {
|
|
|
|
// mdp - first pass
|
|
case 1:
|
|
starts[i+1]++;
|
|
break;
|
|
|
|
// mdp - second pass
|
|
case 2:
|
|
starts[i]++;
|
|
break;
|
|
|
|
// mdp action vector - single pass
|
|
case 3:
|
|
actions[starts[i]] = (int)Cudd_V(dd);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// recurse
|
|
if (dd->index > vars[level]->index) {
|
|
e = t = dd;
|
|
}
|
|
else {
|
|
e = Cudd_E(dd);
|
|
t = Cudd_T(dd);
|
|
}
|
|
|
|
traverse_mtbdd_vect_rec(ddman, e, vars, num_vars, level+1, odd->e, i, code);
|
|
traverse_mtbdd_vect_rec(ddman, t, vars, num_vars, level+1, odd->t, i+odd->eoff, code);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
// compute negative sum of elements in each row
|
|
// if transpose flag is true, matrix was previously transposed so sum for columns instead
|
|
// throws std::bad_alloc on out-of-memory
|
|
|
|
double *rm_negative_row_sums(RMSparseMatrix *rmsm) { return rm_negative_row_sums(rmsm, false); }
|
|
double *cm_negative_row_sums(CMSparseMatrix *cmsm) { return cm_negative_row_sums(cmsm, false); }
|
|
double *cmsr_negative_row_sums(CMSRSparseMatrix *cmsrsm) { return cmsr_negative_row_sums(cmsrsm, false); }
|
|
double *cmsc_negative_row_sums(CMSCSparseMatrix *cmscsm) { return cmsc_negative_row_sums(cmscsm, false); }
|
|
|
|
double *rm_negative_row_sums(RMSparseMatrix *rmsm, bool transpose)
|
|
{
|
|
int i, j, l, h;
|
|
double *diags = NULL;
|
|
int n = rmsm->n;
|
|
double *non_zeros = rmsm->non_zeros;
|
|
unsigned char *row_counts = rmsm->row_counts;
|
|
int *row_starts = (int *)rmsm->row_counts;
|
|
bool use_counts = rmsm->use_counts;
|
|
unsigned int *cols = rmsm->cols;
|
|
|
|
// allocate new vector
|
|
diags = new double[n];
|
|
for (i = 0; i < n; i++) {
|
|
diags[i] = 0;
|
|
}
|
|
// loop through rows
|
|
h = 0;
|
|
for (i = 0; i < n; i++) {
|
|
// loop through entries in this row
|
|
if (!use_counts) { l = row_starts[i]; h = row_starts[i+1]; }
|
|
else { l = h; h += row_counts[i]; }
|
|
for (j = l; j < h; j++) {
|
|
diags[(transpose?cols[j]:i)] -= non_zeros[j];
|
|
}
|
|
}
|
|
|
|
return diags;
|
|
}
|
|
|
|
double *cm_negative_row_sums(CMSparseMatrix *cmsm, bool transpose)
|
|
{
|
|
int i, j, l, h;
|
|
double *diags = NULL;
|
|
int n = cmsm->n;
|
|
double *non_zeros = cmsm->non_zeros;
|
|
unsigned char *col_counts = cmsm->col_counts;
|
|
int *col_starts = (int *)cmsm->col_counts;
|
|
bool use_counts = cmsm->use_counts;
|
|
unsigned int *rows = cmsm->rows;
|
|
|
|
// allocate new vector
|
|
diags = new double[n];
|
|
for (i = 0; i < n; i++) {
|
|
diags[i] = 0;
|
|
}
|
|
// loop through columns
|
|
h = 0;
|
|
for (i = 0; i < n; i++) {
|
|
// loop through entries in this column
|
|
if (!use_counts) { l = col_starts[i]; h = col_starts[i+1]; }
|
|
else { l = h; h += col_counts[i]; }
|
|
for (j = l; j < h; j++) {
|
|
diags[(transpose?i:rows[j])] -= non_zeros[j];
|
|
}
|
|
}
|
|
|
|
return diags;
|
|
}
|
|
|
|
double *cmsr_negative_row_sums(CMSRSparseMatrix *cmsrsm, bool transpose)
|
|
{
|
|
int i, j, l, h;
|
|
double *diags = NULL;
|
|
int n = cmsrsm->n;
|
|
unsigned char *row_counts = cmsrsm->row_counts;
|
|
int *row_starts = (int *)cmsrsm->row_counts;
|
|
bool use_counts = cmsrsm->use_counts;
|
|
unsigned int *cols = cmsrsm->cols;
|
|
double *dist = cmsrsm->dist;
|
|
int dist_shift = cmsrsm->dist_shift;
|
|
int dist_mask = cmsrsm->dist_mask;
|
|
|
|
// allocate new vector
|
|
diags = new double[n];
|
|
for (i = 0; i < n; i++) {
|
|
diags[i] = 0;
|
|
}
|
|
// loop through rows of submatrix
|
|
h = 0;
|
|
for (i = 0; i < n; i++) {
|
|
// loop through entries in this row
|
|
if (!use_counts) { l = row_starts[i]; h = row_starts[i+1]; }
|
|
else { l = h; h += row_counts[i]; }
|
|
for (j = l; j < h; j++) {
|
|
diags[(transpose?((int)(cols[j] >> dist_shift)):i)] -= dist[(int)(cols[j] & dist_mask)];
|
|
}
|
|
}
|
|
|
|
return diags;
|
|
}
|
|
|
|
double *cmsc_negative_row_sums(CMSCSparseMatrix *cmscsm, bool transpose)
|
|
{
|
|
int i, j, l, h;
|
|
double *diags = NULL;
|
|
int n = cmscsm->n;
|
|
unsigned char *col_counts = cmscsm->col_counts;
|
|
int *col_starts = (int *)cmscsm->col_counts;
|
|
bool use_counts = cmscsm->use_counts;
|
|
unsigned int *rows = cmscsm->rows;
|
|
double *dist = cmscsm->dist;
|
|
int dist_shift = cmscsm->dist_shift;
|
|
int dist_mask = cmscsm->dist_mask;
|
|
|
|
// allocate new vector
|
|
diags = new double[n];
|
|
for (i = 0; i < n; i++) {
|
|
diags[i] = 0;
|
|
}
|
|
// loop through columns of submatrix
|
|
h = 0;
|
|
for (i = 0; i < n; i++) {
|
|
// loop through entries in this column
|
|
if (!use_counts) { l = col_starts[i]; h = col_starts[i+1]; }
|
|
else { l = h; h += col_counts[i]; }
|
|
for (j = l; j < h; j++) {
|
|
diags[(transpose?i:((int)(rows[j] >> dist_shift)))] -= dist[(int)(rows[j] & dist_mask)];
|
|
}
|
|
}
|
|
|
|
return diags;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|