-
Notifications
You must be signed in to change notification settings - Fork 32
Expand file tree
/
Copy pathGraphGenerator.h
More file actions
375 lines (352 loc) · 7.93 KB
/
Copy pathGraphGenerator.h
File metadata and controls
375 lines (352 loc) · 7.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
#pragma once
#include <stdint.h>
#include <cmath>
#include <cstdlib>
#include <utility>
struct ExternalId
{
explicit ExternalId( uint64_t id )
: id( id )
{
}
uint64_t id;
};
struct InternalId
{
explicit InternalId( uint32_t id )
: id( id )
{
}
uint32_t id; // 0 to edge_count - 1
};
struct NodeId
{
explicit NodeId( uint32_t id )
: id( id )
{
}
uint32_t id; // 0 to node_count - 1
};
struct Coordinates
{
Coordinates( uint32_t x, uint32_t y )
: x( x )
, y( y )
{
}
uint32_t x;
uint32_t y;
};
enum class Direction : uint8_t
{
POSITIVE = 0,
NEGATIVE = 1
};
/// Generates a simple grid graph with random attributes on edges
class GraphGenerator
{
public:
class NodeRange;
class Edge
{
public:
InternalId id( ) const;
ExternalId external_id( ) const;
uint32_t length_m( ) const; // 0 - 1.000.000
bool is_a( ) const;
bool is_b( ) const;
bool is_c( ) const;
bool is_d( ) const;
bool is_e( Direction ) const;
bool is_f( Direction ) const;
bool is_g( Direction ) const;
uint8_t frc( ) const; // 0-4
uint8_t speed_km_h( Direction ) const;
NodeRange from_node( ) const;
NodeRange to_node( ) const;
private:
friend class GraphGenerator;
Edge( uint32_t id, uint32_t diameter );
uint32_t m_id;
uint32_t m_diameter;
};
class EdgeRange
{
public:
EdgeRange( );
void operator++( );
void operator++( int );
bool valid( ) const;
size_t size( ) const;
Direction dir( ) const;
Edge data( ) const;
private:
friend class GraphGenerator;
EdgeRange( uint32_t node, uint32_t current, uint32_t diameter );
uint32_t m_node;
uint32_t m_current;
uint32_t m_diameter;
};
class NodeRange
{
public:
NodeRange( );
void operator++( );
void operator++( int );
bool valid( ) const;
size_t size( ) const;
NodeId id( ) const;
Coordinates coordinates( ) const;
EdgeRange edges( ) const;
private:
friend class GraphGenerator;
NodeRange( uint32_t current, uint32_t end, uint32_t diameter );
uint32_t m_current;
uint32_t m_end;
uint32_t m_diameter;
};
public:
explicit GraphGenerator( uint32_t num_nodes );
uint32_t node_count( ) const;
uint32_t edge_count( ) const;
NodeRange nodes( ) const;
Edge find( ExternalId ) const;
Edge edge( InternalId ) const;
private:
uint32_t m_num_nodes;
uint32_t m_diameter;
};
inline GraphGenerator::GraphGenerator( uint32_t num_nodes )
{ // round up
m_diameter = ceil( sqrt( num_nodes ) );
m_num_nodes = m_diameter * m_diameter;
}
inline GraphGenerator::NodeRange
GraphGenerator::nodes( ) const
{
return NodeRange( 0, m_num_nodes, m_diameter );
}
inline uint32_t
GraphGenerator::node_count( ) const
{
return m_num_nodes;
}
inline uint32_t
GraphGenerator::edge_count( ) const
{
return m_num_nodes * 2;
}
inline GraphGenerator::Edge
GraphGenerator::find( ExternalId id ) const
{
return Edge( id.id >> 32, m_diameter );
}
inline GraphGenerator::Edge
GraphGenerator::edge( InternalId id ) const
{
return Edge( id.id, m_diameter );
}
inline GraphGenerator::NodeRange::NodeRange( )
: m_current( 0 )
, m_end( 0 )
{
}
inline GraphGenerator::NodeRange::NodeRange( uint32_t current, uint32_t end, uint32_t diameter )
: m_current( current )
, m_end( end )
, m_diameter( diameter )
{
}
inline void
GraphGenerator::NodeRange::operator++( )
{
m_current++;
}
inline void
GraphGenerator::NodeRange::operator++( int )
{
m_current++;
}
inline bool
GraphGenerator::NodeRange::valid( ) const
{
return m_current < m_end;
}
inline size_t
GraphGenerator::NodeRange::size( ) const
{
return m_end - m_current;
}
inline NodeId
GraphGenerator::NodeRange::id( ) const
{
return NodeId{ m_current };
}
inline Coordinates
GraphGenerator::NodeRange::coordinates( ) const
{
uint32_t x = m_current % m_diameter;
uint32_t y = m_current / m_diameter;
x <<= 16;
x |= y;
y <<= 16;
y |= x;
return Coordinates{ x, y };
}
inline GraphGenerator::EdgeRange
GraphGenerator::NodeRange::edges( ) const
{
return EdgeRange( m_current, 0, m_diameter );
}
GraphGenerator::EdgeRange::EdgeRange( )
: m_node( 0 )
, m_current( 4 )
{
}
GraphGenerator::EdgeRange::EdgeRange( uint32_t node, uint32_t current, uint32_t diameter )
: m_node( node )
, m_current( current )
, m_diameter( diameter )
{
}
void
GraphGenerator::EdgeRange::operator++( )
{
m_current++;
}
void
GraphGenerator::EdgeRange::operator++( int )
{
m_current++;
}
bool
GraphGenerator::EdgeRange::valid( ) const
{
return m_current < 4;
}
size_t
GraphGenerator::EdgeRange::size( ) const
{
return 4 - m_current;
}
Direction
GraphGenerator::EdgeRange::dir( ) const
{
return m_current < 2 ? Direction::POSITIVE : Direction::NEGATIVE;
}
GraphGenerator::Edge
GraphGenerator::EdgeRange::data( ) const
{
uint32_t x = m_node % m_diameter;
uint32_t y = m_node / m_diameter;
uint32_t previous_x = ( ( x + m_diameter - 1 ) % m_diameter );
uint32_t previous_y = ( ( y + m_diameter - 1 ) % m_diameter );
if ( m_current == 0 )
return Edge( x + 2 * y * m_diameter, m_diameter );
if ( m_current == 1 )
return Edge( x + ( 2 * y + 1 ) * m_diameter, m_diameter );
if ( m_current == 2 )
return Edge( previous_x + 2 * y * m_diameter, m_diameter );
return Edge( x + ( 2 * previous_y + 1 ) * m_diameter, m_diameter );
}
GraphGenerator::Edge::Edge( uint32_t id, uint32_t diameter )
: m_id( id )
, m_diameter( diameter )
{
}
InternalId
GraphGenerator::Edge::id( ) const
{
return InternalId{ m_id };
}
ExternalId
GraphGenerator::Edge::external_id( ) const
{
return ExternalId{ ( static_cast< uint64_t >( m_id ) << 32 ) | ( m_id * 13 ) };
}
uint32_t
GraphGenerator::Edge::length_m( ) const
{
return 100 + ( ( m_id % 37 ) % 30 ) - 15;
}
bool
GraphGenerator::Edge::is_a( ) const
{
return ( ( m_id % 37 ) & 2 ) != 0;
}
bool
GraphGenerator::Edge::is_b( ) const
{
return ( ( m_id % 1013 ) & 2 ) != 0;
}
bool
GraphGenerator::Edge::is_c( ) const
{
return ( ( m_id % 587 ) & 2 ) != 0;
}
bool
GraphGenerator::Edge::is_d( ) const
{
return ( ( m_id % 7853 ) & 2 ) != 0;
}
bool
GraphGenerator::Edge::is_e( Direction ) const
{
return ( ( m_id % 6967 ) & 2 ) != 0;
}
bool
GraphGenerator::Edge::is_f( Direction ) const
{
return ( ( m_id % 5741 ) & 2 ) != 0;
}
bool
GraphGenerator::Edge::is_g( Direction ) const
{
return ( ( m_id % 5881 ) & 2 ) != 0;
}
uint8_t
GraphGenerator::Edge::frc( ) const
{
uint32_t x = m_id % m_diameter;
uint32_t y = m_id / m_diameter / 2;
bool horizontal = ( ( m_id / m_diameter ) & 1 ) == 0;
uint32_t value = y;
if ( horizontal )
value = x;
if ( ( value & 1 ) == 0 )
return 4;
if ( ( value & 2 ) == 0 )
return 3;
if ( ( value & 4 ) == 0 )
return 2;
if ( ( value & 8 ) == 0 )
return 1;
return 0;
}
uint8_t
GraphGenerator::Edge::speed_km_h( Direction dir ) const
{
uint8_t table[ 5 ] = { 30, 40, 50, 60, 70 };
if ( dir == Direction::POSITIVE )
return table[ frc( ) ];
return table[ frc( ) ] - 1;
}
GraphGenerator::NodeRange
GraphGenerator::Edge::from_node( ) const
{
uint32_t x = m_id % m_diameter;
uint32_t y = m_id / m_diameter / 2;
return NodeRange( x + y * m_diameter, x + y * m_diameter + 1, m_diameter );
}
GraphGenerator::NodeRange
GraphGenerator::Edge::to_node( ) const
{
uint32_t x = m_id % m_diameter;
uint32_t y = m_id / m_diameter / 2;
bool horizontal = ( ( m_id / m_diameter ) & 1 ) == 0;
if ( horizontal )
x = ( x + 1 ) % m_diameter;
else
y = ( y + 1 ) % m_diameter;
return NodeRange( x + y * m_diameter, x + y * m_diameter + 1, m_diameter );
}