python: add bindings for BuDDy's minterms_of

minterms_of was introduced in BuDDy with Spot 2.10, but
wasn't properly binded in Python.

* python/buddy.i: Add bindings.
* tests/python/bdditer.py: Test them.
This commit is contained in:
Alexandre Duret-Lutz 2024-03-11 17:38:52 +01:00
parent 0d4e93a4ec
commit 75e552fdac
2 changed files with 107 additions and 0 deletions

View file

@ -57,14 +57,82 @@
%module buddy %module buddy
%include "std_string.i" %include "std_string.i"
%include "std_container.i"
%{ %{
#include <sstream> #include <sstream>
#include <iterator>
#include "bddx.h" #include "bddx.h"
#include "fddx.h" #include "fddx.h"
#include "bvecx.h" #include "bvecx.h"
%} %}
// Swig come with iterators that implement a decrement method. This
// is not supported in our "successor" iterators.
%fragment("ForwardNullTerminatedIterator_T","header",fragment="SwigPyIterator_T") {
namespace swig
{
template<typename OutIterator,
typename ValueType =
typename std::iterator_traits<OutIterator>::value_type,
typename FromOper = from_oper<ValueType> >
class ForwardNullTerminatedIterator_T : public SwigPyIterator
{
public:
FromOper from;
typedef OutIterator out_iterator;
typedef ValueType value_type;
typedef SwigPyIterator base;
ForwardNullTerminatedIterator_T(out_iterator curr, PyObject *seq)
: SwigPyIterator(seq), current(curr)
{
}
PyObject *value() const {
if (current == nullptr) {
throw stop_iteration();
} else {
return from(static_cast<value_type>(*(current)));
}
}
SwigPyIterator *copy() const
{
return new ForwardNullTerminatedIterator_T(*this);
}
SwigPyIterator *incr(size_t n = 1)
{
while (n--) {
if (current == nullptr) {
throw stop_iteration();
} else {
++current;
}
}
return this;
}
protected:
out_iterator current;
};
template<typename OutIter>
inline SwigPyIterator*
make_forward_null_terminated_iterator(const OutIter& begin, PyObject *seq = 0)
{
return new ForwardNullTerminatedIterator_T<OutIter>(begin, seq);
}
}}
%fragment("ForwardNullTerminatedIterator_T");
%traits_swigtype(bdd);
%fragment(SWIG_Traits_frag(bdd));
%typemap(in) (int* input_buf, int input_buf_size) { %typemap(in) (int* input_buf, int input_buf_size) {
if (!PySequence_Check($input)) if (!PySequence_Check($input))
{ {
@ -362,3 +430,36 @@ class bvec
return (*self)[i]; return (*self)[i];
} }
} }
class minterms_of
{
public:
class minterm_iterator
{
public:
minterm_iterator(minterms_of* me);
minterm_iterator& operator++();
void operator++(int);
bool operator==(std::nullptr_t) const;
bool operator!=(std::nullptr_t) const;
bdd operator*() const;
};
minterms_of(bdd fun, bdd vars);
~minterms_of();
minterm_iterator begin();
std::nullptr_t end() const;
bool done() const;
bdd operator*() const;
void operator++();
};
%extend minterms_of {
%newobject __iter__(PyObject **PYTHON_SELF);
swig::SwigPyIterator* __iter__(PyObject **PYTHON_SELF)
{
return swig::make_forward_null_terminated_iterator(self->begin(),
*PYTHON_SELF);
}
}

View file

@ -65,6 +65,12 @@ del res2
del c del c
gcollect() gcollect()
res3 = []
for i in buddy.minterms_of(buddy.bddtrue, run.aut.ap_vars()):
res3.append(str(spot.bdd_to_formula(i)))
tc.assertEqual(res3, ['!a & !b', '!a & b', 'a & !b', 'a & b'])
gcollect()
f = spot.bdd_to_formula(b) f = spot.bdd_to_formula(b)
tc.assertTrue(f._is(spot.op_And)) tc.assertTrue(f._is(spot.op_And))
tc.assertTrue(f[0]._is(spot.op_ap)) tc.assertTrue(f[0]._is(spot.op_ap))