1 #ifndef _GRAPH_HPP_FDAJIOQ
2 #define _GRAPH_HPP_FDAJIOQ
3 
4 #include "vec1.hpp"
5 #include <set>
6 
7 // Store an edge for an edge-coloured graph.
8 // We require users only give non-negative colours,
9 // we use negative colours to represent reversed direction edges
10 class ColEdge {
11   int tar;
12   int col;
13 public:
ColEdge(int _target,int _colour)14   ColEdge(int _target, int _colour)
15   : tar(_target),
16     col(_colour)
17   { D_ASSERT(tar > 0); }
18 
ColEdge(std::pair<int,int> p)19   ColEdge(std::pair<int, int> p)
20   : tar(p.first),
21     col(p.second)
22   { D_ASSERT(tar > 0); }
23 
24   // we want to allow colour = 0
flipped() const25   ColEdge flipped() const
26   {
27     ColEdge c(tar, 0);
28     c.col = -1 - col;
29     return c;
30   }
31 
target() const32   int target() const { return tar; }
colour() const33   int colour() const { return col; }
34 
type()35   static std::string type()
36   { return "coloured edge"; }
37 
operator ==(const ColEdge & lhs,const ColEdge & rhs)38   friend bool operator==(const ColEdge& lhs, const ColEdge& rhs)
39   { return lhs.tar == rhs.tar && lhs.col == rhs.col; }
40 
operator <(const ColEdge & lhs,const ColEdge & rhs)41   friend bool operator<(const ColEdge& lhs, const ColEdge& rhs)
42   {
43     if(lhs.tar < rhs.tar) return true;
44     if(lhs.tar > rhs.tar) return false;
45     if(lhs.col < rhs.col) return true;
46     if(lhs.col > rhs.col) return false;
47     return false;
48   }
49 
operator <<(std::ostream & o,ColEdge c)50   friend std::ostream& operator<<(std::ostream& o, ColEdge c) {
51       return o << "(" << c.target() << ":c" << c.colour() << ")";
52   }
53 };
54 
55 
56 // Fake implementation of an coloured edge, for uncoloured graphs!
57 class UncolouredEdge {
58   unsigned int tar:31;
59   unsigned int orient:1;
60 public:
UncolouredEdge(int _target,int _colour=0)61   UncolouredEdge(int _target, int _colour = 0)
62   : tar(_target),
63     orient(_colour)
64   {
65     D_ASSERT(_target > 0);
66     D_ASSERT(_colour == 0 || _colour == 1);
67   }
68 
69   // we want to allow colour = 0
flipped() const70   UncolouredEdge flipped() const
71   {
72     UncolouredEdge c(tar, 1 - orient);
73     return c;
74   }
75 
target() const76   int target() const { return tar; }
colour() const77   int colour() const { return orient; }
78 
type()79   static std::string type() {
80     return "uncoloured edge" ;
81   }
82 
operator ==(const UncolouredEdge & lhs,const UncolouredEdge & rhs)83   friend bool operator==(const UncolouredEdge& lhs, const UncolouredEdge& rhs)
84   { return lhs.tar == rhs.tar && lhs.orient == rhs.orient; }
85 
operator <(const UncolouredEdge & lhs,const UncolouredEdge & rhs)86   friend bool operator<(const UncolouredEdge& lhs, const UncolouredEdge& rhs)
87   {
88     if(lhs.tar < rhs.tar) return true;
89     if(lhs.tar > rhs.tar) return false;
90     if(lhs.orient < rhs.orient) return true;
91     if(lhs.orient > rhs.orient) return false;
92     return false;
93   }
94 
operator <<(std::ostream & o,UncolouredEdge c)95   friend std::ostream& operator<<(std::ostream& o, UncolouredEdge c) {
96       return o << "(" << c.target() << ":o" << c.colour() << ")";
97   }
98 };
99 
100 // This file stores some simple generic graph related structures
101 
102 enum GraphDirected
103 { GraphDirected_no = 0, GraphDirected_yes = 1};
104 
105 struct ParsedGraph
106 {
107 	int graph_size;
108 	std::vector<std::set<int> > parts;
109 	vec1<vec1<UncolouredEdge> > edges;
110 
ParsedGraphParsedGraph111 	ParsedGraph(int _size = 0) : graph_size(_size), edges(_size)
112 	{ }
113 
make_symmetricParsedGraph114 	void make_symmetric()
115 	{
116 		for(int i : range1(graph_size))
117 		{
118 			for(int j : range1(edges[i].size()))
119 			{
120         edges[edges[i][j].target()].push_back(UncolouredEdge(j));
121 			}
122 		}
123 	}
124 
cleanParsedGraph125 	void clean()
126 	{
127 		for(int i : range1(graph_size))
128 		{
129 			std::set<UncolouredEdge> e(edges[i].begin(), edges[i].end());
130 			edges[i] = vec1<UncolouredEdge>(e.begin(), e.end());
131 		}
132 	}
133 };
134 
135 // Takes a graph with multi-coloured (and possibly multiple occurrences)
136 // of edges, and replaces it with one where there is at most one edge between
137 // each pair of vertices.
compressGraph(const vec1<vec1<ColEdge>> & graph)138 inline vec1<vec1<ColEdge> > compressGraph(const vec1<vec1<ColEdge> >& graph)
139 {
140   std::map<std::multiset<int>, int> seen_maps;
141 
142   vec1<vec1<ColEdge> > output_graph(graph.size());
143   for(int i : range1(graph.size()) ) {
144     std::map<int, std::multiset<int> > edges;
145     for(int j : range1(graph[i].size()) ) {
146       edges[graph[i][j].target()].insert(graph[i][j].colour());
147     }
148 
149     for(auto & edge : edges)
150     {
151       if(seen_maps.count(edge.second) == 0) {
152         int val = seen_maps.size() + 1;
153         seen_maps[edge.second] = val;
154       }
155       output_graph[i].push_back(ColEdge(edge.first, seen_maps[edge.second]));
156     }
157   }
158   return output_graph;
159 }
160 
compressGraph(const vec1<vec1<UncolouredEdge>> & graph)161 inline vec1<vec1<UncolouredEdge> > compressGraph(const vec1<vec1<UncolouredEdge> >& graph)
162 {
163   return graph;
164 }
165 
166 template<typename VertexType, GraphDirected directed>
167 class Graph
168 {
169   vec1<vec1<VertexType> > edges;
170 public:
Graph(const vec1<vec1<VertexType>> & _points_in,int domain)171   Graph(const vec1<vec1<VertexType> >& _points_in, int domain)
172   {
173     vec1<vec1<VertexType> > _points = compressGraph(_points_in);
174     if(_points.size() > domain)
175       throw GAPException("Graph too large");
176     edges = _points;
177     edges.resize(domain);
178 
179     for(int i : range1(_points.size()))
180     {
181         int i_size = _points[i].size();
182         for(int j : range1(i_size) )
183         {
184             if(_points[i][j].target() <= 0 || _points[i][j].target() > domain) {
185                 throw GAPException("Graph contains out-of-bounds vertex: " + toString(_points[i][j].target()));
186             }
187 
188             if(_points[i][j].colour() < 0 ) {
189                 throw GAPException(" Graph contains invalid edge colour: " + toString(_points[i][j].colour()));
190             }
191             VertexType edge(i, _points[i][j].colour());
192             if(directed)
193             {
194               edge = edge.flipped();
195             }
196 
197             edges[_points[i][j].target()].push_back(edge);
198         }
199     }
200     for(int i : range1(edges.size()))
201     {
202         std::set<VertexType> pntset(edges[i].begin(), edges[i].end());
203         edges[i] = vec1<VertexType>(pntset.begin(), pntset.end());
204     }
205   }
206 
neighbours(int i) const207   const vec1<VertexType>& neighbours(int i) const
208   { return edges[i]; }
209 
vertices() const210   int vertices() const
211   { return edges.size(); }
212 
operator <<(std::ostream & o,const Graph & g)213   friend std::ostream& operator<<(std::ostream& o, const Graph& g)
214   { return o << g.edges; }
215 };
216 
217 template<typename VertexType>
218 class MapEdgeByPerm
219 {
220    const Permutation* p;
221 public:
MapEdgeByPerm(const Permutation * _p)222    MapEdgeByPerm(const Permutation* _p)
223    : p(_p)
224    { }
225 
operator ()(const VertexType & v) const226    VertexType operator()(const VertexType& v) const
227    {
228      VertexType mapvert((*p)[v.target()], v.colour());
229      debug_out(3, "mebp", "mapping " << v << " to " << mapvert);
230      return mapvert;
231    }
232 };
233 
234 template<typename T>
235 class PermutedGraph;
236 
237 template<typename VertexType, GraphDirected directed>
238 class PermutedGraph<Graph<VertexType, directed> >
239 {
240   const Graph<VertexType,directed>* graph;
241   Permutation p;
242   Permutation pinv;
243 public:
PermutedGraph(const Graph<VertexType,directed> * _g,Permutation _p)244   PermutedGraph(const Graph<VertexType, directed>* _g, Permutation _p)
245   : graph(_g), p(_p), pinv(invertPermutation(_p))
246   { }
247 
vertices() const248   int vertices() const
249   { return graph->vertices(); }
250 
neighbours(int i) const251   auto neighbours(int i)  const
252   {
253     debug_out(3, "pg", "mapping " << i << " to " << p[i]);
254     return maprange(graph->neighbours(p[i]), MapEdgeByPerm<VertexType>(&pinv));
255   }
256 };
257 
258 // store how to configure graph propagators
259 struct GraphConfig
260 {
261     int start_path_length;
262     int normal_path_length;
GraphConfigGraphConfig263     GraphConfig(int spl = 1, int npl = 1)
264     : start_path_length(spl), normal_path_length(npl)
265     { }
266 
GraphConfigGraphConfig267     GraphConfig(const GraphConfig& gc)
268     : start_path_length(gc.start_path_length), normal_path_length(gc.normal_path_length)
269     { }
270 };
271 
272 #endif
273