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