spot/buddy/src/bvec.c
Alexandre Duret-Lutz 605dce2aac * configure.ac, Makefile.am, src/Makefile.am, doc/Makefile.am,
examples/Makefile.am, examples/Makefile.def,
examples/adder/Makefile.am, examples/calculator/Makefile.am,
examples/cmilner/Makefile.am, examples/fdd/Makefile.am,
examples/internal/Makefile.am, examples/milner/Makefile.am,
examples/money/Makefile.am, examples/queen/Makefile.am,
examples/solitar/Makefile.am, m4/debug.m4, m4/gccwarns.m4,
ChangeLog, INSTALL: New files.
* config, makefile, src/makefile, doc/makefile,
examples/adder/makefile, examples/calculator/makefile
examples/cmilner/makefile, examples/fdd/makefile,
examples/internal/makefile, examples/milner/makefile,
examples/money/makefile, examples/queen/makefile,
examples/solitare/makefile : Delete.
* examples/adder/adder.cxx, examples/fdd/statespace.cxx,
examples/internal/bddtest.cxx, examples/milner/milner.cxx,
examples/money/money.cxx, examples/queen/queen.cxx,
examples/solitare/solitare.cxx: Include iostream.
* examples/calculator/parser.y: Rename as ...
* examples/calculator/parser.yxx: ... this.  Remove spurious
comas in %token, %right, and %left arguments.
* examples/calculator/parser.h: Rename as ...
* examples/calculator/parser_.h: ... this, because the bison
rule with output parser.h (not tokens.h) from parser.y.
* examples/calculator/lexer.l: Rename as ...
* examples/calculator/lexer.lxx: ... this.  Include parser.h
instead of tokens.h.
* examples/calculator/slist.h
(voidSList::voisSListElem, SList::ite): Fix friend usage.
* src/kernel.h (DEFAULT_CLOCK): Default to 60 if not already
defined.
* README: Update build instruction, and file listing.
2003-05-05 13:44:49 +00:00

1352 lines
35 KiB
C

/*========================================================================
Copyright (C) 1996-2002 by Jorn Lind-Nielsen
All rights reserved
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, reproduce, prepare derivative
works, distribute, and display this software and its documentation
for any purpose, provided that (1) the above copyright notice and
the following two paragraphs appear in all copies of the source code
and (2) redistributions, including without limitation binaries,
reproduce these notices in the supporting documentation. Substantial
modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided
that the new terms are clearly indicated in all files where they apply.
IN NO EVENT SHALL JORN LIND-NIELSEN, OR DISTRIBUTORS OF THIS
SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE
ABOVE PARTIES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
JORN LIND-NIELSEN SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO
OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
========================================================================*/
/*************************************************************************
$Header: /Volumes/CVS/repository/spot/spot/buddy/src/bvec.c,v 1.2 2003/05/05 13:45:05 aduret Exp $
FILE: bvec.c
DESCR: Boolean vector arithmetics using BDDs
AUTH: Jorn Lind
DATE: (C) may 1999
*************************************************************************/
#include <stdlib.h>
#include "kernel.h"
#include "bvec.h"
#define DEFAULT(v) { v.bitnum=0; v.bitvec=NULL; }
/*************************************************************************
*************************************************************************/
static bvec bvec_build(int bitnum, int isTrue)
{
bvec vec;
int n;
vec.bitvec = NEW(BDD,bitnum);
vec.bitnum = bitnum;
if (!vec.bitvec)
{
bdd_error(BDD_MEMORY);
vec.bitnum = 0;
return vec;
}
for (n=0 ; n<bitnum ; n++)
if (isTrue)
vec.bitvec[n] = BDDONE;
else
vec.bitvec[n] = BDDZERO;
return vec;
}
#if 0
int bvec_val2bitnum(int val)
{
int bitnum=0;
while (val > 0)
{
val >>= 1;
bitnum++;
}
return bitnum;
}
#endif
/*
NAME {* bvec\_copy *}
SECTION {* bvec *}
SHORT {* create a copy of a bvec *}
PROTO {* bvec bvec_copy(bvec src) *}
DESCR {* Returns a copy of {\tt src}. The result is reference counted. *}
ALSO {* bvec\_con *}
*/
bvec bvec_copy(bvec src)
{
bvec dst;
int n;
if (src.bitnum == 0)
{
DEFAULT(dst);
return dst;
}
dst = bvec_build(src.bitnum,0);
for (n=0 ; n<src.bitnum ; n++)
dst.bitvec[n] = bdd_addref( src.bitvec[n] );
dst.bitnum = src.bitnum;
return dst;
}
/*
NAME {* bvec\_true *}
SECTION {* bvec *}
SHORT {* build a vector of constant true BDDs *}
PROTO {* bvec bvec_true(int bitnum) *}
DESCR {* Builds a boolean vector with {\tt bitnum} elements, each of which
are the constant true BDD. *}
RETURN {* The boolean vector (which is already reference counted) *}
ALSO {* bvec\_false, bvec\_con, bvec\_var *}
*/
bvec bvec_true(int bitnum)
{
return bvec_build(bitnum, 1);
}
/*
NAME {* bvec\_false *}
SECTION {* bvec *}
SHORT {* build a vector of constant false BDDs *}
PROTO {* bvec bvec_false(int bitnum) *}
DESCR {* Builds a boolean vector with {\tt bitnum} elements, each of which
are the constant false BDD. *}
RETURN {* The boolean vector (which is already reference counted) *}
ALSO {* bvec\_true, bvec\_con, bvec\_var *}
*/
bvec bvec_false(int bitnum)
{
return bvec_build(bitnum, 0);
}
/*
NAME {* bvec\_con *}
SECTION {* bvec *}
SHORT {* Build a boolean vector representing an integer value *}
PROTO {* bvec bvec_con(int bitnum, int val) *}
DESCR {* Builds a boolean vector that represents the value {\tt val}
using {\tt bitnum} bits. The value will be represented with the
LSB at the position 0 and the MSB at position {\tt bitnum}-1.*}
RETURN {* The boolean vector (which is already reference counted) *}
ALSO {* bvec\_true, bvec\_false, bvec\_var *}
*/
bvec bvec_con(int bitnum, int val)
{
bvec v = bvec_build(bitnum,0);
int n;
for (n=0 ; n<v.bitnum ; n++)
{
if (val & 0x1)
v.bitvec[n] = bddtrue;
else
v.bitvec[n] = bddfalse;
val = val >> 1;
}
return v;
}
/*
NAME {* bvec\_var *}
SECTION {* bvec *}
SHORT {* build a boolean vector with BDD variables *}
PROTO {* bvec bvec_var(int bitnum, int offset, int step) *}
DESCR {* Builds a boolean vector with the BDD variables $v_1, \ldots,
v_n$ as the elements. Each variable will be the the variabled
numbered {\tt offset + N*step} where {\tt N} ranges from 0 to
{\tt bitnum}-1.*}
RETURN {* The boolean vector (which is already reference counted) *}
ALSO {* bvec\_true, bvec\_false, bvec\_con *}
*/
bvec bvec_var(int bitnum, int offset, int step)
{
bvec v;
int n;
v = bvec_build(bitnum,0);
for (n=0 ; n<bitnum ; n++)
v.bitvec[n] = bdd_ithvar(offset+n*step);
return v;
}
/*
NAME {* bvec\_varfdd *}
SECTION {* bvec *}
SHORT {* build a boolean vector from a FDD variable block *}
PROTO {* bvec bvec_varfdd(int var) *}
DESCR {* Builds a boolean vector which will include exactly the
variables used to define the FDD variable block {\tt var}. The
vector will have the LSB at position zero. *}
RETURN {* The boolean vector (which is already reference counted) *}
ALSO {* bvec\_var *}
*/
bvec bvec_varfdd(int var)
{
bvec v;
int *bddvar = fdd_vars(var);
int varbitnum = fdd_varnum(var);
int n;
if (bddvar == NULL)
{
DEFAULT(v);
return v;
}
v = bvec_build(varbitnum,0);
for (n=0 ; n<v.bitnum ; n++)
v.bitvec[n] = bdd_ithvar(bddvar[n]);
return v;
}
/*
NAME {* bvec\_varvec *}
SECTION {* bvec *}
SHORT {* build a boolean vector with the variables passed in an array *}
PROTO {* bvec bvec_varvec(int bitnum, int *var) *}
DESCR {* Builds a boolean vector with the BDD variables listed in
the array {\tt var}. The array must be of size {\tt bitnum}. *}
RETURN {* The boolean vector (which is already reference counted) *}
ALSO {* bvec\_var *}
*/
bvec bvec_varvec(int bitnum, int *var)
{
bvec v;
int n;
v = bvec_build(bitnum,0);
for (n=0 ; n<bitnum ; n++)
v.bitvec[n] = bdd_ithvar(var[n]);
return v;
}
/*
NAME {* bvec\_coerce *}
SECTION {* bvec *}
SHORT {* adjust the size of a boolean vector *}
PROTO {* bvec bvec_coerce(int bitnum, bvec v) *}
DESCR {* Build a boolean vector with {\tt bitnum} elements copied from
{\tt v}. If the number of elements in {\tt v} is greater than
{\tt bitnum} then the most significant bits are removed, otherwise
if number is smaller then the vector is padded with constant
false BDDs (zeros). *}
RETURN {* The new boolean vector (which is already reference counted) *}
*/
bvec bvec_coerce(int bitnum, bvec v)
{
bvec res = bvec_build(bitnum,0);
int minnum = MIN(bitnum, v.bitnum);
int n;
for (n=0 ; n<minnum ; n++)
res.bitvec[n] = bdd_addref( v.bitvec[n] );
return res;
}
/*
NAME {* bvec\_isconst *}
SECTION {* bvec *}
SHORT {* test a vector for constant true/false BDDs *}
PROTO {* int bvec_isconst(bvec v) *}
DESCR {* Returns non-zero if the vector {\tt v} consists of only constant
true or false BDDs. Otherwise zero is returned. This test should
prelude any call to {\tt bvec\_val}. *}
ALSO {* bvec\_val, bvec\_con *}
*/
int bvec_isconst(bvec e)
{
int n;
for (n=0 ; n<e.bitnum ; n++)
if (!ISCONST(e.bitvec[n]))
return 0;
return 1;
}
/*
NAME {* bvec\_val *}
SECTION {* bvec *}
SHORT {* calculate the integer value represented by a boolean vector *}
PROTO {* int bvec_val(bvec v) *}
DESCR {* Calculates the value represented by the bits in {\tt v} assuming
that the vector {\tt v} consists of only constant true
or false BDDs. The LSB is assumed to be at position zero. *}
RETURN {* The integer value represented by {\tt v}. *}
ALSO {* bvec\_isconst, bvec\_con *}
*/
int bvec_val(bvec e)
{
int n, val=0;
for (n=e.bitnum-1 ; n>=0 ; n--)
if (ISONE(e.bitvec[n]))
val = (val << 1) | 1;
else if (ISZERO(e.bitvec[n]))
val = val << 1;
else
return 0;
return val;
}
/*======================================================================*/
/*
NAME {* bvec\_free *}
SECTION {* bvec *}
SHORT {* frees all memory used by a boolean vector *}
PROTO {* void bvec_free(bvec v) *}
DESCR {* Use this function to release any unused boolean vectors. The
decrease of the reference counts on the BDDs in {\tt v} is done
by {\tt bvec\_free}. *}
*/
void bvec_free(bvec v)
{
bvec_delref(v);
free(v.bitvec);
}
/*
NAME {* bvec\_addref *}
SECTION {* bvec *}
SHORT {* increase reference count of a boolean vector *}
PROTO {* bvec bvec_addref(bvec v) *}
DESCR {* Use this function to increase the reference count of all BDDs
in a {\tt v}. Please note that all boolean vectors returned
from BuDDy are reference counted from the beginning. *}
RETURN {* The boolean vector {\tt v} *}
ALSO {* bvec\_delref *}
*/
bvec bvec_addref(bvec v)
{
int n;
for (n=0 ; n<v.bitnum ; n++)
bdd_addref(v.bitvec[n]);
return v;
}
/*
NAME {* bvec\_delref *}
SECTION {* bvec *}
SHORT {* decrease the reference count of a boolean vector *}
PROTO {* bvec bvec_delref(bvec v) *}
DESCR {* Use this function to decrease the reference count of all the
BDDs in {\tt v}. *}
RETURN {* The boolean vector {\tt v} *}
ALSO {* bvec\_addref *}
*/
bvec bvec_delref(bvec v)
{
int n;
for (n=0 ; n<v.bitnum ; n++)
bdd_delref(v.bitvec[n]);
return v;
}
/*======================================================================*/
/*
NAME {* bvec\_map1 *}
SECTION {* bvec *}
SHORT {* map a function onto a boolean vector *}
PROTO {* bvec bvec_map1(bvec a, bdd (*fun)(bdd)) *}
DESCR {* Maps the function {\tt fun} onto all the elements in {\tt a}. The
value returned from {\tt fun} is stored in a new vector which
is then returned. An example of a mapping function is
{\tt bdd\_not} which can be used like this\\
\indent {\tt bvec res = bvec\_map1(a, bdd\_not)}\\
\noindent to negate all the BDDs in {\tt a}.*}
RETURN {* The new vector (which is already reference counted) *}
ALSO {* bvec\_map2, bvec\_map3 *}
*/
bvec bvec_map1(bvec a, BDD (*fun)(BDD))
{
bvec res;
int n;
res = bvec_build(a.bitnum,0);
for (n=0 ; n < a.bitnum ; n++)
res.bitvec[n] = bdd_addref( fun(a.bitvec[n]) );
return res;
}
/*
NAME {* bvec\_map2 *}
SECTION {* bvec *}
SHORT {* map a function onto a boolean vector *}
PROTO {* bvec bvec_map2(bvec a, bvec b, bdd (*fun)(bdd,bdd)) *}
DESCR {* Maps the function {\tt fun} onto all the elements in {\tt a} and
{\tt b}. The value returned from {\tt fun} is stored in a new
vector which is then returned. An example of a mapping function
is {\tt bdd\_and} which can be used like this\\
\indent {\tt bvec res = bvec\_map2(a, b, bdd\_and)}\\
\noindent to calculate the logical 'and' of all the BDDs in
{\tt a} and {\tt b}. *}
RETURN {* The new vector (which is already reference counted) *}
ALSO {* bvec\_map1, bvec\_map3 *}
*/
bvec bvec_map2(bvec a, bvec b, BDD (*fun)(BDD,BDD))
{
bvec res;
int n;
DEFAULT(res);
if (a.bitnum != b.bitnum)
{
bdd_error(BVEC_SIZE);
return res;
}
res = bvec_build(a.bitnum,0);
for (n=0 ; n < a.bitnum ; n++)
res.bitvec[n] = bdd_addref( fun(a.bitvec[n], b.bitvec[n]) );
return res;
}
/*
NAME {* bvec\_map3 *}
SECTION {* bvec *}
SHORT {* map a function onto a boolean vector *}
PROTO {* bvec bvec_map3(bvec a, bvec b, bvec c, bdd (*fun)(bdd,bdd,bdd)) *}
DESCR {* Maps the function {\tt fun} onto all the elements in {\tt a},
{\tt b} and {\tt c}. The value returned from {\tt fun} is stored
in a new vector which is then returned. An example of a mapping
function is {\tt bdd\_ite} which can be used like this\\
\indent {\tt bvec res = bvec\_map3(a, b, c, bdd\_ite) }\\
\noindent to calculate the if-then-else function for each element
in {\tt a}, {\tt b} and {\tt c}. *}
RETURN {* The new vector (which is already reference counted) *}
ALSO {* bvec\_map1, bvec\_map2 *}
*/
bvec bvec_map3(bvec a, bvec b, bvec c, BDD (*fun)(BDD,BDD,BDD))
{
bvec res;
int n;
DEFAULT(res);
if (a.bitnum != b.bitnum || b.bitnum != c.bitnum)
{
bdd_error(BVEC_SIZE);
return res;
}
res = bvec_build(a.bitnum,0);
for (n=0 ; n < a.bitnum ; n++)
res.bitvec[n] = bdd_addref( fun(a.bitvec[n], b.bitvec[n], c.bitvec[n]) );
return res;
}
/*======================================================================*/
/*
NAME {* bvec\_add *}
SECTION {* bvec *}
SHORT {* builds a boolean vector for addition *}
PROTO {* bvec bvec_add(bvec l, bvec r) *}
DESCR {* Builds a new boolean vector that represents the addition of two
other vectors. Each element $x_i$ in the result will represent
the function
\[ x_i = l_i\ \mbox{xor}\ r_i\ \mbox{xor}\ c_{i-1} \]
where the carry in $c_i$ is
\[ c_i = (l_i\ \mbox{and}\ r_i)\ \mbox{or}\ (c_{i-1}\ \mbox{and}
\ (l_i\ \mbox{or}\ r_i)). \]
It is important for efficency that the BDD
variables used in {\tt l} and {\tt r} are interleaved. *}
RETURN {* The result of the addition (which is already reference counted) *}
ALSO {* bvec\_sub, bvec\_mul, bvec\_shl *}
*/
bvec bvec_add(bvec l, bvec r)
{
bvec res;
BDD c = bddfalse;
int n;
if (l.bitnum == 0 || r.bitnum == 0)
{
DEFAULT(res);
return res;
}
if (l.bitnum != r.bitnum)
{
bdd_error(BVEC_SIZE);
DEFAULT(res);
return res;
}
res = bvec_build(l.bitnum,0);
for (n=0 ; n<res.bitnum ; n++)
{
BDD tmp1, tmp2, tmp3;
/* bitvec[n] = l[n] ^ r[n] ^ c; */
tmp1 = bdd_addref( bdd_apply(l.bitvec[n], r.bitvec[n], bddop_xor) );
tmp2 = bdd_addref( bdd_apply(tmp1, c, bddop_xor) );
bdd_delref(tmp1);
res.bitvec[n] = tmp2;
/* c = (l[n] & r[n]) | (c & (l[n] | r[n])); */
tmp1 = bdd_addref( bdd_apply(l.bitvec[n], r.bitvec[n], bddop_or) );
tmp2 = bdd_addref( bdd_apply(c, tmp1, bddop_and) );
bdd_delref(tmp1);
tmp1 = bdd_addref( bdd_apply(l.bitvec[n], r.bitvec[n], bddop_and) );
tmp3 = bdd_addref( bdd_apply(tmp1, tmp2, bddop_or) );
bdd_delref(tmp1);
bdd_delref(tmp2);
bdd_delref(c);
c = tmp3;
}
bdd_delref(c);
return res;
}
/*
NAME {* bvec\_sub *}
SECTION {* bvec *}
SHORT {* builds a boolean vector for subtraction *}
PROTO {* bvec bvec_sub(bvec l, bvec r) *}
DESCR {* Builds a new boolean vector that represents the subtraction of two
other vectors. Each element $x_i$ in the result will represent
the function
\[ x_i = l_i\ \mbox{xor}\ r_i\ \mbox{xor}\ c_{i-1} \]
where the carry in $c_i$ is
\[ c_i = (l_i\ \mbox{and}\ r_i\ \mbox{and}\ c_{i-1})\
\mbox{or}\ (\mbox{not}\ l_i\ \mbox{and}
\ (r_i\ \mbox{or}\ c_{i-1})). \]
It is important for efficency that the BDD
variables used in {\tt l} and {\tt r} are interleaved. *}
RETURN {* The result of the subtraction (which is already reference counted) *}
ALSO {* bvec\_add, bvec\_mul, bvec\_shl *}
*/
bvec bvec_sub(bvec l, bvec r)
{
bvec res;
BDD c = bddfalse;
int n;
if (l.bitnum == 0 || r.bitnum == 0)
{
DEFAULT(res);
return res;
}
if (l.bitnum != r.bitnum)
{
bdd_error(BVEC_SIZE);
DEFAULT(res);
return res;
}
res = bvec_build(l.bitnum,0);
for (n=0 ; n<res.bitnum ; n++)
{
BDD tmp1, tmp2, tmp3;
/* bitvec[n] = l[n] ^ r[n] ^ c; */
tmp1 = bdd_addref( bdd_apply(l.bitvec[n], r.bitvec[n], bddop_xor) );
tmp2 = bdd_addref( bdd_apply(tmp1, c, bddop_xor) );
bdd_delref(tmp1);
res.bitvec[n] = tmp2;
/* c = (l[n] & r[n] & c) | (!l[n] & (r[n] | c)); */
tmp1 = bdd_addref( bdd_apply(r.bitvec[n], c, bddop_or) );
tmp2 = bdd_addref( bdd_apply(l.bitvec[n], tmp1, bddop_less) );
bdd_delref(tmp1);
tmp1 = bdd_addref( bdd_apply(l.bitvec[n], r.bitvec[n], bddop_and) );
tmp3 = bdd_addref( bdd_apply(tmp1, c, bddop_and) );
bdd_delref(tmp1);
tmp1 = bdd_addref( bdd_apply(tmp3, tmp2, bddop_or) );
bdd_delref(tmp2);
bdd_delref(tmp3);
bdd_delref(c);
c = tmp1;
}
bdd_delref(c);
return res;
}
/*
NAME {* bvec\_mulfixed *}
SECTION {* bvec *}
SHORT {* builds a boolean vector for multiplication with a constant *}
PROTO {* bvec bvec_mulfixed(bvec e, int c) *}
DESCR {* Builds a boolean vector representing the multiplication
of {\tt e} and {\tt c}. *}
RETURN {* The result of the multiplication (which is already reference counted) *}
ALSO {* bvec\_mul, bvec\_div, bvec\_add, bvec\_shl *}
*/
bvec bvec_mulfixed(bvec e, int c)
{
bvec res, next, rest;
int n;
if (e.bitnum == 0)
{
DEFAULT(res);
return res;
}
if (c == 0)
return bvec_build(e.bitnum,0); /* return false array (base case) */
next = bvec_build(e.bitnum,0);
for (n=1 ; n<e.bitnum ; n++)
/* e[] is never deleted, so no ref.cou. */
next.bitvec[n] = e.bitvec[n-1];
rest = bvec_mulfixed(next, c>>1);
if (c & 0x1)
{
res = bvec_add(e, rest);
bvec_free(rest);
}
else
res = rest;
bvec_free(next);
return res;
}
/*
NAME {* bvec\_mul *}
SECTION {* bvec *}
SHORT {* builds a boolean vector for multiplication *}
PROTO {* bvec bvec_mul(bvec l, bvec r) *}
DESCR {* Builds a boolean vector representing the multiplication
of {\tt l} and {\tt r}. *}
RETURN {* The result of the multiplication (which is already reference counted) *}
ALSO {* bvec\_mulfixed, bvec\_div, bvec\_add, bvec\_shl *}
*/
bvec bvec_mul(bvec left, bvec right)
{
int n;
int bitnum = left.bitnum + right.bitnum;
bvec res;
bvec leftshifttmp;
bvec leftshift;
if (left.bitnum == 0 || right.bitnum == 0)
{
DEFAULT(res);
return res;
}
res = bvec_false(bitnum);
leftshifttmp = bvec_copy(left);
leftshift = bvec_coerce(bitnum, leftshifttmp);
/*bvec_delref(leftshifttmp);*/
bvec_free(leftshifttmp);
for (n=0 ; n<right.bitnum ; n++)
{
bvec added = bvec_add(res, leftshift);
int m;
for (m=0 ; m<bitnum ; m++)
{
bdd tmpres = bdd_addref( bdd_ite(right.bitvec[n],
added.bitvec[m], res.bitvec[m]) );
bdd_delref(res.bitvec[m]);
res.bitvec[m] = tmpres;
}
/* Shift 'leftshift' one bit left */
bdd_delref(leftshift.bitvec[leftshift.bitnum-1]);
for (m=bitnum-1 ; m>=1 ; m--)
leftshift.bitvec[m] = leftshift.bitvec[m-1];
leftshift.bitvec[0] = bddfalse;
/*bvec_delref(added);*/
bvec_free(added);
}
/*bvec_delref(leftshift);*/
bvec_free(leftshift);
return res;
}
static void bvec_div_rec(bvec divisor, bvec *remainder, bvec *result, int step)
{
int n;
BDD isSmaller = bdd_addref( bvec_lte(divisor, *remainder) );
bvec newResult = bvec_shlfixed( *result, 1, isSmaller );
bvec zero = bvec_build(divisor.bitnum, bddfalse);
bvec newRemainder, tmp, sub = bvec_build(divisor.bitnum, bddfalse);
for (n=0 ; n<divisor.bitnum ; n++)
sub.bitvec[n] = bdd_ite(isSmaller, divisor.bitvec[n], zero.bitvec[n]);
tmp = bvec_sub( *remainder, sub );
newRemainder = bvec_shlfixed(tmp, 1, result->bitvec[divisor.bitnum-1]);
if (step > 1)
bvec_div_rec( divisor, &newRemainder, &newResult, step-1 );
bvec_free(tmp);
bvec_free(sub);
bvec_free(zero);
bdd_delref(isSmaller);
bvec_free(*remainder);
bvec_free(*result);
*result = newResult;
*remainder = newRemainder;
}
/*
NAME {* bvec\_divfixed *}
SECTION {* bvec *}
SHORT {* builds a boolean vector for division by a constant *}
PROTO {* int bvec_div(bvec e, int c, bvec *res, bvec *rem) *}
DESCR {* Builds a new boolean vector representing the integer division
of {\tt e} with {\tt c}. The result of the division will be stored
in {\tt res} and the remainder of the division will be stored in
{\tt rem}. Both vectors should be initialized as the function
will try to release the nodes used by them. If an error occurs then
the nodes will {\em not} be freed. *}
RETURN {* Zero on success or a negative error code on error. *}
ALSO {* bvec\_div, bvec\_mul, bvec\_add, bvec\_shl *}
*/
int bvec_divfixed(bvec e, int c, bvec *res, bvec *rem)
{
if (c > 0)
{
bvec divisor = bvec_con(e.bitnum, c);
bvec tmp = bvec_build(e.bitnum, 0);
bvec tmpremainder = bvec_shlfixed(tmp, 1, e.bitvec[e.bitnum-1]);
bvec result = bvec_shlfixed(e, 1, bddfalse);
bvec remainder;
bvec_div_rec(divisor, &tmpremainder, &result, divisor.bitnum);
remainder = bvec_shrfixed(tmpremainder, 1, bddfalse);
bvec_free(tmp);
bvec_free(tmpremainder);
bvec_free(divisor);
*res = result;
*rem = remainder;
return 0;
}
return bdd_error(BVEC_DIVZERO);
}
#if 0
void p(bvec x)
{
int n;
for (n=0 ; n<x.bitnum ; n++)
{
printf(" %d: ", n);
fdd_printset(x.bitvec[n]);
printf("\n");
}
}
#endif
/*
NAME {* bvec\_div *}
SECTION {* bvec *}
SHORT {* builds a boolean vector for division *}
PROTO {* int bvec_div(bvec l, bvec r, bvec *res, bvec *rem) *}
DESCR {* Builds a new boolean vector representing the integer division
of {\tt l} with {\tt r}. The result of the division will be stored
in {\tt res} and the remainder of the division will be stored in
{\tt rem}. Both vectors should be initialized as the function
will try to release the nodes used by them. If an error occurs then
the nodes will {\em not} be freed.*}
RETURN {* Zero on success or a negative error code on error. *}
ALSO {* bvec\_mul, bvec\_divfixed, bvec\_add, bvec\_shl *}
*/
int bvec_div(bvec left, bvec right, bvec *result, bvec *remainder)
{
int n, m;
int bitnum = left.bitnum + right.bitnum;
bvec res;
bvec rem;
bvec div, divtmp;
if (left.bitnum == 0 || right.bitnum == 0 ||
left.bitnum != right.bitnum)
{
return bdd_error(BVEC_SIZE);
}
rem = bvec_coerce(bitnum, left);
divtmp = bvec_coerce(bitnum, right);
div = bvec_shlfixed(divtmp, left.bitnum, bddfalse);
/*bvec_delref(divtmp);*/
bvec_free(divtmp);
res = bvec_false(right.bitnum);
for (n=0 ; n<right.bitnum+1 ; n++)
{
bdd divLteRem = bdd_addref( bvec_lte(div, rem) );
bvec remSubDiv = bvec_sub(rem, div);
for (m=0 ; m<bitnum ; m++)
{
bdd remtmp = bdd_addref( bdd_ite(divLteRem,
remSubDiv.bitvec[m],rem.bitvec[m]) );
bdd_delref( rem.bitvec[m] );
rem.bitvec[m] = remtmp;
}
if (n > 0)
res.bitvec[right.bitnum-n] = divLteRem;
/* Shift 'div' one bit right */
bdd_delref(div.bitvec[0]);
for (m=0 ; m<bitnum-1 ; m++)
div.bitvec[m] = div.bitvec[m+1];
div.bitvec[bitnum-1] = bddfalse;
/*bvec_delref(remSubDiv);*/
bvec_free(remSubDiv);
}
/*bvec_delref(*result);*/
bvec_free(*result);
/*bvec_delref(*remainder);*/
bvec_free(*remainder);
*result = res;
*remainder = bvec_coerce(right.bitnum, rem);
/*bvec_delref(rem);*/
bvec_free(rem);
return 0;
}
/*
NAME {* bvec\_ite *}
SECTION {* bvec *}
SHORT {* calculates the if-then-else operator for a boolean vector *}
PROTO {* bvec bvec_ite(bdd a, bvec b, bvec c) *}
DESCR {* Builds a vector where the bdd {\tt a} has been applied bitwise to
{\tt b} and {\tt c} in an if-then-else operation, such that
the result $r$ is:
\[
r_i = ite(a,b_i,c_i);
\] *}
RETURN {* The if-then-else result. *}
ALSO {* bdd\_ite *}
*/
bvec bvec_ite(bdd a, bvec b, bvec c)
{
bvec res;
int n;
DEFAULT(res);
if (b.bitnum != c.bitnum)
{
bdd_error(BVEC_SIZE);
return res;
}
res = bvec_build(b.bitnum, 0);
for (n=0 ; n<b.bitnum ; ++n)
{
res.bitvec[n] = bdd_addref( bdd_ite(a, b.bitvec[n], c.bitvec[n]) );
}
return res;
}
/*
NAME {* bvec\_shlfixed *}
SECTION {* bvec *}
SHORT {* shift left operation (fixed number of bits) *}
PROTO {* bvec bvec_shlfixed(bvec v, int pos, BDD c) *}
DESCR {* Builds a boolean vector that represents {\tt v} shifted {\tt pos}
times to the left. The new empty elements will be set to {\tt c}.*}
RETURN {* The result of the operation (which is already reference counted) *}
ALSO {* bvec\_add, bvec\_mul, bvec\_shl, bvec\_shr *}
*/
bvec bvec_shlfixed(bvec e, int pos, BDD c)
{
bvec res;
int n, minnum = MIN(e.bitnum,pos);
if (pos < 0)
{
bdd_error(BVEC_SHIFT);
DEFAULT(res);
return res;
}
if (e.bitnum == 0)
{
DEFAULT(res);
return res;
}
res = bvec_build(e.bitnum,0);
for (n=0 ; n<minnum ; n++)
res.bitvec[n] = bdd_addref(c);
for (n=minnum ; n<e.bitnum ; n++)
res.bitvec[n] = bdd_addref(e.bitvec[n-pos]);
return res;
}
/*
NAME {* bvec\_shl *}
SECTION {* bvec *}
SHORT {* shift left operation (symbolic) *}
PROTO {* bvec bvec_shl(bvec l, bvec r, BDD c) *}
DESCR {* Builds a boolean vector that represents {\tt l} shifted {\tt r}
times to the left. The new empty elements will be set to {\tt c}.
The shift operation is fully symbolic and the number of bits
shifted depends on the current value encoded by {\tt r}. *}
RETURN {* The result of the operation (which is already reference counted) *}
ALSO {* bvec\_add, bvec\_mul, bvec\_shlfixed, bvec\_shr *}
*/
BVEC bvec_shl(BVEC l, BVEC r, BDD c)
{
BVEC res, val;
bdd tmp1, tmp2, rEquN;
int n, m;
if (l.bitnum == 0 || r.bitnum == 0)
{
DEFAULT(res);
return res;
}
res = bvec_build(l.bitnum, 0);
for (n=0 ; n<=l.bitnum ; n++)
{
val = bvec_con(r.bitnum, n);
rEquN = bdd_addref( bvec_equ(r, val) );
for (m=0 ; m<l.bitnum ; m++)
{
/* Set the m'th new location to be the (m+n)'th old location */
if (m-n >= 0)
tmp1 = bdd_addref( bdd_and(rEquN, l.bitvec[m-n]) );
else
tmp1 = bdd_addref( bdd_and(rEquN, c) );
tmp2 = bdd_addref( bdd_or(res.bitvec[m], tmp1) );
bdd_delref(tmp1);
bdd_delref(res.bitvec[m]);
res.bitvec[m] = tmp2;
}
bdd_delref(rEquN);
/*bvec_delref(val);*/
bvec_free(val);
}
/* At last make sure 'c' is shiftet in for r-values > l-bitnum */
val = bvec_con(r.bitnum, l.bitnum);
rEquN = bvec_gth(r, val);
tmp1 = bdd_addref( bdd_and(rEquN, c) );
for (m=0 ; m<l.bitnum ; m++)
{
tmp2 = bdd_addref( bdd_or(res.bitvec[m], tmp1) );
bdd_delref(res.bitvec[m]);
res.bitvec[m] = tmp2;
}
bdd_delref(tmp1);
bdd_delref(rEquN);
/*bvec_delref(val);*/
bvec_free(val);
return res;
}
/*
NAME {* bvec\_shrfixed *}
SECTION {* bvec *}
SHORT {* shift right operation *}
PROTO {* bvec bvec_shrfixed(bvec v, int pos, BDD c) *}
DESCR {* Builds a boolean vector that represents {\tt v} shifted {\tt pos}
times to the right. The new empty elements will be set to {\tt c}.*}
RETURN {* The result of the operation (which is already reference counted) *}
ALSO {* bvec\_add, bvec\_mul, bvec\_shr, bvec\_shl *}
*/
bvec bvec_shrfixed(bvec e, int pos, BDD c)
{
bvec res;
int n, maxnum = MAX(0,e.bitnum-pos);
if (pos < 0)
{
bdd_error(BVEC_SHIFT);
DEFAULT(res);
return res;
}
if (e.bitnum == 0)
{
DEFAULT(res);
return res;
}
res = bvec_build(e.bitnum,0);
for (n=maxnum ; n<e.bitnum ; n++)
res.bitvec[n] = bdd_addref(c);
for (n=0 ; n<maxnum ; n++)
res.bitvec[n] = bdd_addref(e.bitvec[n+pos]);
return res;
}
/*
NAME {* bvec\_shr *}
SECTION {* bvec *}
SHORT {* shift right operation (symbolic) *}
PROTO {* bvec bvec_shr(bvec l, bvec r, BDD c) *}
DESCR {* Builds a boolean vector that represents {\tt l} shifted {\tt r}
times to the right. The new empty elements will be set to {\tt c}.
The shift operation is fully symbolic and the number of bits
shifted depends on the current value encoded by {\tt r}. *}
RETURN {* The result of the operation (which is already reference counted) *}
ALSO {* bvec\_add, bvec\_mul, bvec\_shl, bvec\_shrfixed *}
*/
BVEC bvec_shr(BVEC l, BVEC r, BDD c)
{
BVEC res, val;
bdd tmp1, tmp2, rEquN;
int n, m;
if (l.bitnum == 0 || r.bitnum == 0)
{
DEFAULT(res);
return res;
}
res = bvec_build(l.bitnum, 0);
for (n=0 ; n<=l.bitnum ; n++)
{
val = bvec_con(r.bitnum, n);
rEquN = bdd_addref( bvec_equ(r, val) );
for (m=0 ; m<l.bitnum ; m++)
{
/* Set the m'th new location to be the (m+n)'th old location */
if (m+n <= 2)
tmp1 = bdd_addref( bdd_and(rEquN, l.bitvec[m+n]) );
else
tmp1 = bdd_addref( bdd_and(rEquN, c) );
tmp2 = bdd_addref( bdd_or(res.bitvec[m], tmp1) );
bdd_delref(tmp1);
bdd_delref(res.bitvec[m]);
res.bitvec[m] = tmp2;
}
bdd_delref(rEquN);
/*bvec_delref(val);*/
bvec_free(val);
}
/* At last make sure 'c' is shiftet in for r-values > l-bitnum */
val = bvec_con(r.bitnum, l.bitnum);
rEquN = bvec_gth(r, val);
tmp1 = bdd_addref( bdd_and(rEquN, c) );
for (m=0 ; m<l.bitnum ; m++)
{
tmp2 = bdd_addref( bdd_or(res.bitvec[m], tmp1) );
bdd_delref(res.bitvec[m]);
res.bitvec[m] = tmp2;
}
bdd_delref(tmp1);
bdd_delref(rEquN);
/*bvec_delref(val);*/
bvec_free(val);
return res;
}
/*
NAME {* bvec\_lth *}
SECTION {* bvec *}
SHORT {* calculates the truth value of $x < y$ *}
PROTO {* bdd bvec_lth(bvec l, bvec r) *}
DESCR {* Returns the BDD representing {\tt l < r}
({\em not} reference counted). Both vectors must have the
same number of bits. *}
ALSO {* bvec\_lte, bvec\_gth, bvec\_gte, bvec\_equ, bvec\_neq *}
*/
bdd bvec_lth(bvec l, bvec r)
{
BDD p = bddfalse;
int n;
if (l.bitnum == 0 || r.bitnum == 0)
return bddfalse;
if (l.bitnum != r.bitnum)
{
bdd_error(BVEC_SIZE);
return p;
}
for (n=0 ; n<l.bitnum ; n++)
{
/* p = (!l[n] & r[n]) |
* bdd_apply(l[n], r[n], bddop_biimp) & p; */
BDD tmp1 = bdd_addref(bdd_apply(l.bitvec[n],r.bitvec[n],bddop_less));
BDD tmp2 = bdd_addref(bdd_apply(l.bitvec[n],r.bitvec[n],bddop_biimp));
BDD tmp3 = bdd_addref( bdd_apply(tmp2, p, bddop_and) );
BDD tmp4 = bdd_addref( bdd_apply(tmp1, tmp3, bddop_or) );
bdd_delref(tmp1);
bdd_delref(tmp2);
bdd_delref(tmp3);
bdd_delref(p);
p = tmp4;
}
return bdd_delref(p);
}
/*
NAME {* bvec\_lte *}
SECTION {* bvec *}
SHORT {* calculates the truth value of $x \leq y$ *}
PROTO {* bdd bvec_lte(bvec l, bvec r) *}
DESCR {* Returns the BDD representing {\tt l}$\leq${\tt r}
({\em not} reference counted). Both vectors must have the
same number of bits. *}
ALSO {* bvec\_lth, bvec\_gth, bvec\_gte, bvec\_equ, bvec\_neq *}
*/
bdd bvec_lte(bvec l, bvec r)
{
BDD p = bddtrue;
int n;
if (l.bitnum == 0 || r.bitnum == 0)
return bddfalse;
if (l.bitnum != r.bitnum)
{
bdd_error(BVEC_SIZE);
return p;
}
for (n=0 ; n<l.bitnum ; n++)
{
/* p = (!l[n] & r[n]) |
* bdd_apply(l[n], r[n], bddop_biimp) & p; */
BDD tmp1 = bdd_addref( bdd_apply(l.bitvec[n], r.bitvec[n], bddop_less) );
BDD tmp2 = bdd_addref( bdd_apply(l.bitvec[n], r.bitvec[n], bddop_biimp) );
BDD tmp3 = bdd_addref( bdd_apply(tmp2, p, bddop_and) );
BDD tmp4 = bdd_addref( bdd_apply(tmp1, tmp3, bddop_or) );
bdd_delref(tmp1);
bdd_delref(tmp2);
bdd_delref(tmp3);
bdd_delref(p);
p = tmp4;
}
return bdd_delref(p);
}
/*
NAME {* bvec\_gth *}
SECTION {* bvec *}
SHORT {* calculates the truth value of $x > y$ *}
PROTO {* bdd bvec_gth(bvec l, bvec r) *}
DESCR {* Returns the BDD representing {\tt l > r}
({\em not} reference counted). Both vectors must have the
same number of bits. *}
ALSO {* bvec\_lth, bvec\_lte, bvec\_gte, bvec\_equ, bvec\_neq *}
*/
bdd bvec_gth(bvec l, bvec r)
{
BDD tmp = bdd_addref( bvec_lte(l,r) );
BDD p = bdd_not(tmp);
bdd_delref(tmp);
return p;
}
/*
NAME {* bvec\_gte *}
SECTION {* bvec *}
SHORT {* calculates the truth value of $x \geq y$ *}
PROTO {* bdd bvec_gte(bvec l, bvec r) *}
DESCR {* Returns the BDD representing {\tt l}$\geq${\tt r}
({\em not} reference counted). Both vectors must have the
same number of bits. *}
ALSO {* bvec\_lth, bvec\_gth, bvec\_gth, bvec\_equ, bvec\_neq *}
*/
bdd bvec_gte(bvec l, bvec r)
{
BDD tmp = bdd_addref( bvec_lth(l,r) );
BDD p = bdd_not(tmp);
bdd_delref(tmp);
return p;
}
/*
NAME {* bvec\_equ *}
SECTION {* bvec *}
SHORT {* calculates the truth value of $x = y$ *}
PROTO {* bdd bvec_equ(bvec l, bvec r) *}
DESCR {* Returns the BDD representing {\tt l = r}
({\em not} reference counted). Both vectors must have the
same number of bits. *}
ALSO {* bvec\_lth, bvec\_lte, bvec\_gth, bvec\_gte, bvec\_neq *}
*/
bdd bvec_equ(bvec l, bvec r)
{
BDD p = bddtrue;
int n;
if (l.bitnum == 0 || r.bitnum == 0)
return bddfalse;
if (l.bitnum != r.bitnum)
{
bdd_error(BVEC_SIZE);
return p;
}
for (n=0 ; n<l.bitnum ; n++)
{
BDD tmp1, tmp2;
tmp1 = bdd_addref( bdd_apply(l.bitvec[n], r.bitvec[n], bddop_biimp) );
tmp2 = bdd_addref( bdd_apply(tmp1, p, bddop_and) );
bdd_delref(tmp1);
bdd_delref(p);
p = tmp2;
}
return bdd_delref(p);
}
/*
NAME {* bvec\_neq *}
SECTION {* bvec *}
SHORT {* calculates the truth value of $x \neq y$ *}
PROTO {* bdd bvec_neq(bvec l, bvec r) *}
DESCR {* Returns the BDD representing {\tt l}$\neq${\tt r}
({\em not} reference counted). Both vectors must have the
same number of bits. *}
ALSO {* bvec\_lte, bvec\_lth, bvec\_gth, bvec\_gth, bvec\_equ *}
*/
bdd bvec_neq(bvec l, bvec r)
{
BDD tmp = bdd_addref( bvec_equ(l,r) );
BDD p = bdd_not(tmp);
bdd_delref(tmp);
return p;
}
/* EOF */