diff --git a/Makefile b/Makefile index d1619e13e0870c76704655be27be1a4bf336ddef..772fc2c33e25be28119b86269816862d6f0e86ce 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ default: groupConnectivity.so clean_obj -groupConnectivity.so: groupConnectivity.pyx group-connectivity.h setup.py compileTimeOptions.h generateCompileTimeOptions.sh rings.h fast-array.h parmap.py +groupConnectivity.so: groupConnectivity.pyx group-connectivity.h setup.py compileTimeOptions.h generateCompileTimeOptions.sh rings.h fast-array.h twoCuts.h parmap.py ./generateCompileTimeOptions.sh > options.h python setup.py build_ext cp build/lib*/groupConnectivity.so . diff --git a/group-connectivity.h b/group-connectivity.h index fc1b5082ea56a2d6630462d09a0e2e1738053c5b..280b07d1fbddce7c4316d6aff622a25486c57efa 100644 --- a/group-connectivity.h +++ b/group-connectivity.h @@ -1,12 +1,13 @@ #ifndef __GROUP_CONNECTIVITY_H__ #define __GROUP_CONNECTIVITY_H__ +#include <stdlib.h> +#include <stdint.h> #include <vector> #include "options.h" #include "rings.h" #include "fast-array.h" - typedef int EdgeId; typedef int DirectedEdgeId; typedef std::pair<DirectedEdgeId, DirectedEdgeId> TwoCut; @@ -39,6 +40,8 @@ struct Tester : public AbstractTester { typedef typename Ring::T T; typedef ::Mapping<Ring> Mapping; +# include "twoCuts.h" + size_t numForb; int edges; @@ -47,11 +50,14 @@ struct Tester : public AbstractTester { # if EXPLICIT_NORMAL_EDGES std::vector< EdgeId > normalEdges; # endif +# if USE_TWO_CUTS + std::vector< TwoCutInt > twoCuts; +# endif virtual void init( int edges_, std::vector<EdgeId> spanningTree, - std::vector<TwoCut> twoCuts, + std::vector<TwoCut> twoCuts_, std::vector< std::vector<DirectedEdgeId> > elementaryCycles ) { edges = edges_; @@ -64,6 +70,10 @@ struct Tester : public AbstractTester { ClassesType C(num_classes, 0); C.swap(classes); +# if EXPLICIT_NORMAL_EDGES + std::vector<bool> edgeList(edges, 1); +# endif + for (auto e : spanningTree) classEdges.push_back(e - 1); @@ -79,8 +89,25 @@ struct Tester : public AbstractTester { } } +# if USE_TWO_CUTS + for (auto cut : twoCuts_) { + if (cut.first < 0) { + cut.first *= -1; + cut.second *= -1; + } + + TwoCutInt intCut; + intCut.a = cut.first - 1; + intCut.flip = (cut.second < 0); + intCut.b = (intCut.flip ? - cut.second : cut.second) - 1; + + twoCuts.push_back(intCut); + edgeList[intCut.a] = false; + edgeList[intCut.b] = false; + } +# endif + # if EXPLICIT_NORMAL_EDGES - std::vector<bool> edgeList(edges, 1); for (size_t i = 0; i < edges; i++) if (edgeList[i]) normalEdges.push_back(i); # endif @@ -103,6 +130,18 @@ struct Tester : public AbstractTester { } } +# if USE_TWO_CUTS + for (const auto& cut : twoCuts) { + int val = cut.getValue(forb) + 1; + if (val >= cut.max_value) { + cut.encode(forb, 0); + } else { + cut.encode(forb, val); + return true; + } + } +# endif + return false; } #else // !USE_NEXT_FORB @@ -127,6 +166,17 @@ struct Tester : public AbstractTester { map.combine(map[i.first], i.second); } +# if USE_TWO_CUTS + for (const auto &c : twoCuts) { + T m_a = map[c.a]; + T m_b = map[c.b]; + if (map[c.a] > map[c.b]) { + map.assign(c.a, m_b); + map.assign(c.b, m_a); + } + } +# endif + return map; } @@ -138,6 +188,13 @@ struct Tester : public AbstractTester { index += map[i]; } +# if USE_TWO_CUTS + for (const auto& c : twoCuts) { + index *= c.max_value; + index += c.getValue(map); + } +# endif + return index; } @@ -184,5 +241,10 @@ struct Tester : public AbstractTester { virtual ~Tester() {} }; +#if USE_TWO_CUTS +template < typename R > +const typename Tester<R>::TwoCutInt::Tables Tester<R>::TwoCutInt::S; +#endif + #endif diff --git a/twoCuts.h b/twoCuts.h new file mode 100644 index 0000000000000000000000000000000000000000..3a84084f4f8f77e1f5dab5e5b5ba8a54d3e6e56c --- /dev/null +++ b/twoCuts.h @@ -0,0 +1,44 @@ +// Internals of Tester class +#if USE_TWO_CUTS + +struct TwoCutInt { + EdgeId a, b; + bool flip; + + static const int max_value = ((Ring::size - 1) * (Ring::size - 2)) / 2; + + struct Tables { + char decodeMatrix[Ring::size][Ring::size]; + struct { char a, b; } encodeTable[max_value]; + + Tables() { + encodeTable[0] = {1, 2}; + + for (int i = 1; i < max_value; i++) { + bool carry = (encodeTable[i-1].b >= Ring::size); + encodeTable[i].a = encodeTable[i-1].a + carry; + encodeTable[i].b = carry ? encodeTable[i].a + 1 : encodeTable[i-1].b + 1; + } + + memset(decodeMatrix, -1, sizeof(decodeMatrix)); + + for (int i = 0; i < max_value; i++) + decodeMatrix[encodeTable[i].a][encodeTable[i].b] = i; + } + }; + + static const Tables S; + + inline int getValue(const Mapping &map) const { + return S.decodeMatrix[map[a]][flip ? Ring::negate(map[b]) : map[b]]; + } + + inline void encode(Mapping& map, int value) const { + auto vals = S.encodeTable[value]; + map.assign(a, vals.a); + map.assign(b, flip ? Ring::negate(vals.b) : vals.b); + } +}; + +#endif +