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.
519 lines
18 KiB
519 lines
18 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2002-
|
|
// Authors:
|
|
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford, formerly University of Birmingham)
|
|
// Description: C++ code for double vector stuff
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// 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 "dv.h"
|
|
#include <math.h>
|
|
#include <new>
|
|
|
|
// local function prototypes
|
|
|
|
static void mtbdd_to_double_vector_rec(DdManager *ddman, DdNode *dd, DdNode **vars, int num_vars, int level, ODDNode *odd, long o, double *res);
|
|
static DdNode *double_vector_to_mtbdd_rec(DdManager *ddman, double *vec, DdNode **vars, int num_vars, int level, ODDNode *odd, long o);
|
|
static DdNode *double_vector_to_bdd_rec(DdManager *ddman, double *vec, int rel_op, double bound1, double bound2, DdNode **vars, int num_vars, int level, ODDNode *odd, long o);
|
|
static void filter_double_vector_rec(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, int level, ODDNode *odd, long o);
|
|
static double get_first_from_bdd_rec(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, int level, ODDNode *odd, long o);
|
|
static double min_double_vector_over_bdd_rec(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, int level, ODDNode *odd, long o);
|
|
static double max_double_vector_over_bdd_rec(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, int level, ODDNode *odd, long o);
|
|
static double sum_double_vector_over_bdd_rec(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, int level, ODDNode *odd, long o);
|
|
static double sum_double_vector_over_mtbdd_rec(DdManager *ddman, double *vec, DdNode *mult, DdNode **vars, int num_vars, int level, ODDNode *odd, long o);
|
|
static void sum_double_vector_over_dd_vars_rec(DdManager *ddman, double *vec, double *vec2, DdNode **vars, int num_vars, int level, int first_var, int last_var, ODDNode *odd, ODDNode *odd2, long o, long o2);
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// converts an mtbdd representing a vector to an array of doubles
|
|
// it is optional whether or not an array is passed in to be used
|
|
// if so, it should be the right size (as determined by row->eoff+row->toff)
|
|
// if not, a new one is created
|
|
// in either the case, a pointer to the array is returned
|
|
// throws std::bad_alloc on out-of-memory
|
|
|
|
EXPORT double *mtbdd_to_double_vector(DdManager *ddman, DdNode *dd, DdNode **vars, int num_vars, ODDNode *odd)
|
|
{
|
|
return mtbdd_to_double_vector(ddman, dd, vars, num_vars, odd, NULL);
|
|
}
|
|
|
|
EXPORT double *mtbdd_to_double_vector(DdManager *ddman, DdNode *dd, DdNode **vars, int num_vars, ODDNode *odd, double *res)
|
|
{
|
|
int i, n;
|
|
|
|
// determine size
|
|
n = odd->eoff + odd->toff;
|
|
// create array (if not supplied)
|
|
if (!res) res = new double[n];
|
|
// initialise to zero
|
|
for (i = 0; i < n; i++) {
|
|
res[i] = 0.0;
|
|
}
|
|
// build array recursively
|
|
mtbdd_to_double_vector_rec(ddman, dd, vars, num_vars, 0, odd, 0, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
void mtbdd_to_double_vector_rec(DdManager *ddman, DdNode *dd, DdNode **vars, int num_vars, int level, ODDNode *odd, long o, double *res)
|
|
{
|
|
DdNode *e, *t;
|
|
|
|
if (dd == Cudd_ReadZero(ddman)) return;
|
|
|
|
if (level == num_vars) {
|
|
res[o] = Cudd_V(dd);
|
|
return;
|
|
}
|
|
else if (dd->index > vars[level]->index) {
|
|
e = t = dd;
|
|
}
|
|
else {
|
|
e = Cudd_E(dd);
|
|
t = Cudd_T(dd);
|
|
}
|
|
|
|
mtbdd_to_double_vector_rec(ddman, e, vars, num_vars, level+1, odd->e, o, res);
|
|
mtbdd_to_double_vector_rec(ddman, t, vars, num_vars, level+1, odd->t, o+odd->eoff, res);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// converts an array of doubles to an mtbdd
|
|
|
|
EXPORT DdNode *double_vector_to_mtbdd(DdManager *ddman, double *vec, DdNode **vars, int num_vars, ODDNode *odd)
|
|
{
|
|
return double_vector_to_mtbdd_rec(ddman, vec, vars, num_vars, 0, odd, 0);
|
|
}
|
|
|
|
DdNode *double_vector_to_mtbdd_rec(DdManager *ddman, double *vec, DdNode **vars, int num_vars, int level, ODDNode *odd, long o)
|
|
{
|
|
DdNode *e, *t;
|
|
|
|
if (level == num_vars) {
|
|
return DD_Constant(ddman, vec[o]);
|
|
}
|
|
else {
|
|
if (odd->eoff > 0) {
|
|
e = double_vector_to_mtbdd_rec(ddman, vec, vars, num_vars, level+1, odd->e, o);
|
|
}
|
|
else {
|
|
e = DD_Constant(ddman, 0);
|
|
}
|
|
if (odd->toff > 0) {
|
|
t = double_vector_to_mtbdd_rec(ddman, vec, vars, num_vars, level+1, odd->t, o+odd->eoff);
|
|
}
|
|
else {
|
|
t = DD_Constant(ddman, 0);
|
|
}
|
|
if (e == t) {
|
|
Cudd_RecursiveDeref(ddman, t);
|
|
return e;
|
|
}
|
|
else {
|
|
Cudd_Ref(vars[level]);
|
|
return DD_ITE(ddman, vars[level], t, e);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// converts an array of doubles to a bdd using a relational operator and one or more bounds
|
|
|
|
EXPORT DdNode *double_vector_to_bdd(DdManager *ddman, double *vec, int rel_op, double bound, DdNode **vars, int num_vars, ODDNode *odd)
|
|
{
|
|
return double_vector_to_bdd(ddman, vec, rel_op, bound, 0, vars, num_vars, odd);
|
|
}
|
|
|
|
EXPORT DdNode *double_vector_to_bdd(DdManager *ddman, double *vec, int rel_op, double bound1, double bound2, DdNode **vars, int num_vars, ODDNode *odd)
|
|
{
|
|
return double_vector_to_bdd_rec(ddman, vec, rel_op, bound1, bound2, vars, num_vars, 0, odd, 0);
|
|
}
|
|
|
|
DdNode *double_vector_to_bdd_rec(DdManager *ddman, double *vec, int rel_op, double bound1, double bound2, DdNode **vars, int num_vars, int level, ODDNode *odd, long o)
|
|
{
|
|
DdNode *e, *t;
|
|
|
|
if (level == num_vars) {
|
|
switch (rel_op) {
|
|
case DV_GREATER_THAN_EQUALS: return (vec[o] >= bound1) ? DD_Constant(ddman, 1) : DD_Constant(ddman, 0); break;
|
|
case DV_GREATER_THAN: return (vec[o] > bound1) ? DD_Constant(ddman, 1) : DD_Constant(ddman, 0); break;
|
|
case DV_LESS_THAN_EQUALS: return (vec[o] <= bound1) ? DD_Constant(ddman, 1) : DD_Constant(ddman, 0); break;
|
|
case DV_LESS_THAN: return (vec[o] < bound1) ? DD_Constant(ddman, 1) : DD_Constant(ddman, 0); break;
|
|
case DV_INTERVAL: return (vec[o] >= bound1 && vec[o] <= bound2) ? DD_Constant(ddman, 1) : DD_Constant(ddman, 0); break;
|
|
}
|
|
}
|
|
else {
|
|
if (odd->eoff > 0) {
|
|
e = double_vector_to_bdd_rec(ddman, vec, rel_op, bound1, bound2, vars, num_vars, level+1, odd->e, o);
|
|
}
|
|
else {
|
|
e = DD_Constant(ddman, 0);
|
|
}
|
|
if (odd->toff > 0) {
|
|
t = double_vector_to_bdd_rec(ddman, vec, rel_op, bound1, bound2, vars, num_vars, level+1, odd->t, o+odd->eoff);
|
|
}
|
|
else {
|
|
t = DD_Constant(ddman, 0);
|
|
}
|
|
if (e == t) {
|
|
Cudd_RecursiveDeref(ddman, t);
|
|
return e;
|
|
}
|
|
else {
|
|
Cudd_Ref(vars[level]);
|
|
return DD_ITE(ddman, vars[level], t, e);
|
|
}
|
|
}
|
|
// Never get here:
|
|
return NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// filter vector using a bdd (set elements not in filter to 0)
|
|
|
|
EXPORT void filter_double_vector(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, ODDNode *odd)
|
|
{
|
|
filter_double_vector_rec(ddman, vec, filter, vars, num_vars, 0, odd, 0);
|
|
}
|
|
|
|
void filter_double_vector_rec(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, int level, ODDNode *odd, long o)
|
|
{
|
|
DdNode *dd;
|
|
|
|
if (level == num_vars) {
|
|
if (Cudd_V(filter) == 0) {
|
|
vec[o] = 0;
|
|
}
|
|
}
|
|
else {
|
|
if (odd->eoff > 0) {
|
|
dd = (filter->index > vars[level]->index) ? filter : Cudd_E(filter);
|
|
filter_double_vector_rec(ddman, vec, dd, vars, num_vars, level+1, odd->e, o);
|
|
}
|
|
if (odd->toff > 0) {
|
|
dd = (filter->index > vars[level]->index) ? filter : Cudd_T(filter);
|
|
filter_double_vector_rec(ddman, vec, dd, vars, num_vars, level+1, odd->t, o+odd->eoff);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// get value of first element in BDD filter
|
|
|
|
EXPORT double get_first_from_bdd(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, ODDNode *odd)
|
|
{
|
|
// This shouldn't really be called with an empty filter.
|
|
// But we check for this anyway and return NaN.
|
|
// This is unfortunately indistinguishable from the case
|
|
// where the vector does actually contain NaN. Ho hum.
|
|
if (filter == Cudd_ReadZero(ddman)) return NAN;
|
|
// Recurse...
|
|
else return get_first_from_bdd_rec(ddman, vec, filter, vars, num_vars, 0, odd, 0);
|
|
}
|
|
|
|
double get_first_from_bdd_rec(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, int level, ODDNode *odd, long o)
|
|
{
|
|
DdNode *dd;
|
|
|
|
if (level == num_vars) {
|
|
return vec[o];
|
|
}
|
|
else {
|
|
// go down filter along first non-zero path
|
|
dd = (filter->index > vars[level]->index) ? filter : Cudd_E(filter);
|
|
if (dd != Cudd_ReadZero(ddman)) {
|
|
return get_first_from_bdd_rec(ddman, vec, dd, vars, num_vars, level+1, odd->e, o);
|
|
}
|
|
else {
|
|
dd = (filter->index > vars[level]->index) ? filter : Cudd_T(filter);
|
|
return get_first_from_bdd_rec(ddman, vec, dd, vars, num_vars, level+1, odd->t, o+odd->eoff);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// compute the minimum value of those in the bdd passed in
|
|
|
|
EXPORT double min_double_vector_over_bdd(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, ODDNode *odd)
|
|
{
|
|
return min_double_vector_over_bdd_rec(ddman, vec, filter, vars, num_vars, 0, odd, 0);
|
|
}
|
|
|
|
double min_double_vector_over_bdd_rec(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, int level, ODDNode *odd, long o)
|
|
{
|
|
double d1, d2;
|
|
DdNode *dd;
|
|
|
|
if (level == num_vars) {
|
|
if (Cudd_V(filter) > 0) {
|
|
return vec[o];
|
|
}
|
|
else {
|
|
return HUGE_VAL;
|
|
}
|
|
}
|
|
else {
|
|
d1 = d2 = HUGE_VAL;
|
|
if (odd->eoff > 0) {
|
|
dd = (filter->index > vars[level]->index) ? filter : Cudd_E(filter);
|
|
d1 = min_double_vector_over_bdd_rec(ddman, vec, dd, vars, num_vars, level+1, odd->e, o);
|
|
}
|
|
if (odd->toff > 0) {
|
|
dd = (filter->index > vars[level]->index) ? filter : Cudd_T(filter);
|
|
d2 = min_double_vector_over_bdd_rec(ddman, vec, dd, vars, num_vars, level+1, odd->t, o+odd->eoff);
|
|
}
|
|
return (d1 < d2) ? d1 : d2;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// compute the maximum value of those in the bdd passed in
|
|
|
|
EXPORT double max_double_vector_over_bdd(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, ODDNode *odd)
|
|
{
|
|
return max_double_vector_over_bdd_rec(ddman, vec, filter, vars, num_vars, 0, odd, 0);
|
|
}
|
|
|
|
double max_double_vector_over_bdd_rec(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, int level, ODDNode *odd, long o)
|
|
{
|
|
double d1, d2;
|
|
DdNode *dd;
|
|
|
|
if (level == num_vars) {
|
|
if (Cudd_V(filter) > 0) {
|
|
return vec[o];
|
|
}
|
|
else {
|
|
return -HUGE_VAL;
|
|
}
|
|
}
|
|
else {
|
|
d1 = d2 = -HUGE_VAL;
|
|
if (odd->eoff > 0) {
|
|
dd = (filter->index > vars[level]->index) ? filter : Cudd_E(filter);
|
|
d1 = max_double_vector_over_bdd_rec(ddman, vec, dd, vars, num_vars, level+1, odd->e, o);
|
|
}
|
|
if (odd->toff > 0) {
|
|
dd = (filter->index > vars[level]->index) ? filter : Cudd_T(filter);
|
|
d2 = max_double_vector_over_bdd_rec(ddman, vec, dd, vars, num_vars, level+1, odd->t, o+odd->eoff);
|
|
}
|
|
return (d1 > d2) ? d1 : d2;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// sums up the elements of a double array - but only those in the bdd passed in
|
|
|
|
EXPORT double sum_double_vector_over_bdd(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, ODDNode *odd)
|
|
{
|
|
return sum_double_vector_over_bdd_rec(ddman, vec, filter, vars, num_vars, 0, odd, 0);
|
|
}
|
|
|
|
double sum_double_vector_over_bdd_rec(DdManager *ddman, double *vec, DdNode *filter, DdNode **vars, int num_vars, int level, ODDNode *odd, long o)
|
|
{
|
|
double d;
|
|
DdNode *dd;
|
|
|
|
if (level == num_vars) {
|
|
if (Cudd_V(filter) > 0) {
|
|
return vec[o];
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
d = 0;
|
|
if (odd->eoff > 0) {
|
|
dd = (filter->index > vars[level]->index) ? filter : Cudd_E(filter);
|
|
d += sum_double_vector_over_bdd_rec(ddman, vec, dd, vars, num_vars, level+1, odd->e, o);
|
|
}
|
|
if (odd->toff > 0) {
|
|
dd = (filter->index > vars[level]->index) ? filter : Cudd_T(filter);
|
|
d += sum_double_vector_over_bdd_rec(ddman, vec, dd, vars, num_vars, level+1, odd->t, o+odd->eoff);
|
|
}
|
|
return d;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// sums up the elements of a double array - multiplied by the corresponding values in the mtbdd passed in
|
|
|
|
EXPORT double sum_double_vector_over_mtbdd(DdManager *ddman, double *vec, DdNode *mult, DdNode **vars, int num_vars, ODDNode *odd)
|
|
{
|
|
return sum_double_vector_over_mtbdd_rec(ddman, vec, mult, vars, num_vars, 0, odd, 0);
|
|
}
|
|
|
|
double sum_double_vector_over_mtbdd_rec(DdManager *ddman, double *vec, DdNode *mult, DdNode **vars, int num_vars, int level, ODDNode *odd, long o)
|
|
{
|
|
double d;
|
|
DdNode *dd;
|
|
|
|
if (level == num_vars) {
|
|
return Cudd_V(mult) * vec[o];
|
|
}
|
|
else {
|
|
d = 0;
|
|
if (odd->eoff > 0) {
|
|
dd = (mult->index > vars[level]->index) ? mult : Cudd_E(mult);
|
|
d += sum_double_vector_over_mtbdd_rec(ddman, vec, dd, vars, num_vars, level+1, odd->e, o);
|
|
}
|
|
if (odd->toff > 0) {
|
|
dd = (mult->index > vars[level]->index) ? mult : Cudd_T(mult);
|
|
d += sum_double_vector_over_mtbdd_rec(ddman, vec, dd, vars, num_vars, level+1, odd->t, o+odd->eoff);
|
|
}
|
|
return d;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// sum up the elements of a double array, over a subset of its dd vars
|
|
// the dd var subset must be a continuous range of vars, identified by indices: first_var, last_var
|
|
// store the result in the vector vec2
|
|
|
|
EXPORT void sum_double_vector_over_dd_vars(DdManager *ddman, double *vec, double *vec2, DdNode **vars, int num_vars, int first_var, int last_var, ODDNode *odd, ODDNode *odd2)
|
|
{
|
|
return sum_double_vector_over_dd_vars_rec(ddman, vec, vec2, vars, num_vars, 0, first_var, last_var, odd, odd2, 0, 0);
|
|
}
|
|
|
|
void sum_double_vector_over_dd_vars_rec(DdManager *ddman, double *vec, double *vec2, DdNode **vars, int num_vars, int level, int first_var, int last_var, ODDNode *odd, ODDNode *odd2, long o, long o2)
|
|
{
|
|
if (level == num_vars) {
|
|
vec2[o2] += vec[o];
|
|
}
|
|
else {
|
|
if (odd->eoff > 0) {
|
|
if (vars[level]->index >= first_var && vars[level]->index <= last_var) {
|
|
sum_double_vector_over_dd_vars_rec(ddman, vec, vec2, vars, num_vars, level+1, first_var, last_var, odd->e, odd2, o, o2);
|
|
} else {
|
|
sum_double_vector_over_dd_vars_rec(ddman, vec, vec2, vars, num_vars, level+1, first_var, last_var, odd->e, odd2->e, o, o2);
|
|
}
|
|
}
|
|
if (odd->toff > 0) {
|
|
if (vars[level]->index >= first_var && vars[level]->index <= last_var) {
|
|
sum_double_vector_over_dd_vars_rec(ddman, vec, vec2, vars, num_vars, level+1, first_var, last_var, odd->t, odd2, o+odd->eoff, o2);
|
|
} else {
|
|
sum_double_vector_over_dd_vars_rec(ddman, vec, vec2, vars, num_vars, level+1, first_var, last_var, odd->t, odd2->t, o+odd->eoff, o2+odd2->eoff);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Converts an array of doubles to a a DistVector, which stores only one copy of each distinct double
|
|
// and an array of short pointers to them. Fails and returns NULL if there are more distinct values
|
|
// than can be indexed by a short or if we run out of memory.
|
|
|
|
EXPORT DistVector *double_vector_to_dist(double *v, int n)
|
|
{
|
|
double *buffer = NULL, *tmp = NULL;
|
|
int i, j, num_dist, buffer_size, buffer_inc;
|
|
unsigned int max_size;
|
|
unsigned short s, *ptrs = NULL;
|
|
DistVector *dv = NULL;
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
try {
|
|
|
|
// create buffer to store distinct values
|
|
buffer_inc = 256;
|
|
buffer_size = 256;
|
|
max_size = 1 << (8*sizeof(short));
|
|
buffer = new double[buffer_size];
|
|
ptrs = new unsigned short[n];
|
|
|
|
num_dist = 0;
|
|
// go thru vector
|
|
for (i = 0; i < n; i++) {
|
|
// see if we have this distinct val already
|
|
for (s = 0; s < num_dist; s++)
|
|
if (buffer[s] == v[i]) break;
|
|
// add a new val if necessary...
|
|
if (s == num_dist) {
|
|
// ...increasing buffer size if required...
|
|
if (num_dist >= buffer_size) {
|
|
// ...and bailing out if there are too many
|
|
if (buffer_size+buffer_inc > max_size) {
|
|
throw std::bad_alloc();
|
|
}
|
|
tmp = new double[buffer_size+buffer_inc];
|
|
for (j = 0; j < buffer_size; j++) {
|
|
tmp[j] = buffer[j];
|
|
}
|
|
delete[] buffer;
|
|
buffer = tmp;
|
|
buffer_size += buffer_inc;
|
|
}
|
|
// add val
|
|
buffer[s] = v[i];
|
|
num_dist++;
|
|
}
|
|
ptrs[i] = s;
|
|
}
|
|
|
|
// create data str to store result
|
|
dv = new DistVector();
|
|
dv->dist = buffer;
|
|
dv->num_dist = num_dist;
|
|
dv->ptrs = ptrs;
|
|
|
|
// try/catch for memory allocation/deallocation
|
|
} catch(std::bad_alloc e) {
|
|
if (buffer) delete[] buffer;
|
|
if (tmp) delete[] tmp;
|
|
if (ptrs) delete[] ptrs;
|
|
if (dv) delete dv;
|
|
return NULL;
|
|
}
|
|
|
|
return dv;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
// free distinct vector struct
|
|
|
|
EXPORT DistVector::DistVector()
|
|
{
|
|
dist = NULL;
|
|
num_dist = 0;
|
|
ptrs = NULL;
|
|
}
|
|
|
|
EXPORT DistVector::~DistVector()
|
|
{
|
|
if (dist) delete[] dist;
|
|
if (ptrs) delete[] ptrs;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|