Swarm-SLAM  1.0.0
C-SLAM Framework
test_algebraic_connectivity.py
Go to the documentation of this file.
1 import unittest
2 
3 import sys
4 sys.path.append('/home/lajoiepy/Documents/projects/c-slam/c-slam-ws/install/cslam/lib/python3.8/site-packages/')
5 
6 from cslam.algebraic_connectivity_maximization import AlgebraicConnectivityMaximization, EdgeInterRobot
7 from cslam.mac.utils import Edge
8 from cslam.mac.mac import MAC
9 import random
10 import numpy as np
11 from timeit import default_timer as timer
12 import copy
13 
14 
15 def build_simple_graph(nb_poses, nb_candidate_edges):
16  """Build simple graph
17 
18  Args:
19  nb_poses (int): nb of poses in graph
20  nb_candidate_edges (int): nb of loop edges to generate
21 
22  Returns:
23  list(EdgeInterRobot), dict(EdgeInterRobot): edges in the graph
24  """
25  fixed_weight = 1
26  fixed_edges_list = []
27 
28  candidate_edges = {}
29  i = 0
30  while len(candidate_edges.values()) < nb_candidate_edges:
31  edge = EdgeInterRobot(0, random.choice(range(nb_poses)), 0,
32  random.choice(range(nb_poses)), fixed_weight)
33  candidate_edges[(edge.robot0_keyframe_id, edge.robot1_keyframe_id)] = edge
34  i = i + 1
35  return fixed_edges_list, list(candidate_edges.values())
36 
37 
38 def build_multi_robot_graph(nb_poses, nb_candidate_edges, max_nb_robots):
39  """Build graph with multiple robots
40 
41  Args:
42  nb_poses (int): nb of poses in graph
43  nb_candidate_edges (int): nb of loop edges to generate
44  max_nb_robots (int): nb of robots
45 
46  Returns:
47  list(EdgeInterRobot), dict(EdgeInterRobot): edges in the graph
48  """
49  fixed_weight = 1
50  fixed_edges_list = []
51 
52  # Enforce connectivity
53  for i in range(max_nb_robots - 1):
54  edge = EdgeInterRobot(i, nb_poses - 1, i + 1, nb_poses - 1,
55  fixed_weight)
56  fixed_edges_list.append(edge)
57 
58  # Add inter-robot candidates
59  candidate_edges = {}
60  i = 0
61  while len(candidate_edges.values()) < nb_candidate_edges:
62  robot0_id = random.choice(range(max_nb_robots))
63  robot1_id = random.choice(
64  list(set(range(max_nb_robots)) - set([robot0_id])))
65  edge = EdgeInterRobot(robot0_id,
66  random.choice(range(nb_poses)), robot1_id,
67  random.choice(range(nb_poses)), fixed_weight)
68  if edge.robot0_id < edge.robot1_id:
69  candidate_edges[(edge.robot0_id, edge.robot0_keyframe_id, edge.robot1_id, edge.robot1_keyframe_id)] = edge
70  else:
71  candidate_edges[(edge.robot1_id, edge.robot1_keyframe_id, edge.robot0_id, edge.robot0_keyframe_id)] = edge
72  i = i + 1
73 
74  return fixed_edges_list, list(candidate_edges.values())
75 
76 
77 class TestAlgebraicConnectivity(unittest.TestCase):
78  """Unit tests for algebraic connectivity maximization
79  """
80 
81  def test_simple_graph(self):
82  """Test simple single robot graph
83  """
84  # Build simple graph
85  nb_poses = 100
86  nb_candidate_edges = 50
87  fixed_edges_list, candidate_edges_list = build_simple_graph(
88  nb_poses, nb_candidate_edges)
89 
90  nb_candidates_to_choose = 10
91 
93  ac.set_graph(fixed_edges_list, candidate_edges_list)
94  start = timer()
95  is_robot_considered = {0: True}
96  selection = ac.select_candidates(nb_candidates_to_choose,
97  is_robot_considered,
98  greedy_initialization=False)
99  stop = timer()
100  self.assertEqual(len(selection), nb_candidates_to_choose)
101 
103  """Test the greedy weight initialization
104  """
105  nb_candidates_to_choose = 10
106  nb_poses = 100
107  nb_candidate_edges = 50
108  fixed_edges_list, candidate_edges_list = build_simple_graph(
109  nb_poses, nb_candidate_edges)
110  weights = np.random.rand(nb_candidate_edges)
112  i = 0
113  for e in range(len(candidate_edges_list)):
114  candidate_edges_list[e] = ac.replace_weight(candidate_edges_list[e],
115  weight=weights[i])
116  i = i + 1
117  ac.set_graph(fixed_edges_list, candidate_edges_list)
118  is_robot_considered = {0: True}
119  is_robot_included = ac.check_graph_disconnections(is_robot_considered)
120  ac.compute_offsets(is_robot_included)
121  edges = ac.rekey_edges(ac.candidate_edges.values(), is_robot_included)
122  w_init = ac.greedy_initialization(nb_candidates_to_choose, edges)
123  self.assertAlmostEqual(
124  np.sum(weights[w_init.astype(bool)]),
125  np.sum(np.sort(weights)[-nb_candidates_to_choose:]))
126 
128  """Test that adding measurements after solving works
129  """
130  # Build simple graph
131  nb_poses = 100
132  nb_candidate_edges = 50
133  nb_candidates_to_choose = 10
134  fixed_edges_list, candidate_edges_list = build_simple_graph(
135  nb_poses, nb_candidate_edges)
137  ac.set_graph(fixed_edges_list, candidate_edges_list)
138 
139  # Solve the initial graph
140  is_robot_considered = {0: True}
141  selection0 = ac.select_candidates(nb_candidates_to_choose,
142  is_robot_considered,
143  greedy_initialization=False)
144  self.assertEqual(len(selection0), nb_candidates_to_choose)
145 
146  # Add edges
147  nb_add_edges = 10
148  for i in range(nb_add_edges):
149  ac.add_candidate_edge(
150  EdgeInterRobot(0, random.choice(range(nb_poses)), 0,
151  random.choice(range(nb_poses)), 1.0))
152  selection1 = ac.select_candidates(nb_candidates_to_choose,
153  is_robot_considered,
154  greedy_initialization=False)
155  self.assertEqual(len(selection1), nb_candidates_to_choose)
156 
157  selection2 = ac.select_candidates(nb_candidates_to_choose + 2,
158  is_robot_considered,
159  greedy_initialization=False)
160  self.assertEqual(len(selection2), nb_candidates_to_choose + 2)
161  for i in range(nb_add_edges):
162  ac.add_candidate_edge(
163  EdgeInterRobot(0, random.choice(range(nb_poses)), 0,
164  random.choice(range(nb_poses)), 1.0))
165  selection3 = ac.select_candidates(nb_candidates_to_choose + 2,
166  is_robot_considered,
167  greedy_initialization=False)
168  self.assertEqual(len(selection3), nb_candidates_to_choose + 2)
169 
171  """Test that loop closures can be fixed
172  """
173  # Build simple graph
174  nb_poses = 100
175  nb_candidate_edges = 50
176  nb_candidates_to_choose = 10
177  fixed_edges_list, candidate_edges_list = build_simple_graph(
178  nb_poses, nb_candidate_edges)
180  ac.set_graph(fixed_edges_list, candidate_edges_list)
181 
182  # Solve the initial graph
183  is_robot_considered = {0: True}
184  selection0 = ac.select_candidates(nb_candidates_to_choose,
185  is_robot_considered,
186  greedy_initialization=False)
187  self.assertEqual(len(selection0), nb_candidates_to_choose)
188 
189  # Add edges
190  nb_add_edges = 10
191  for i in range(nb_add_edges):
192  ac.add_fixed_edge(
193  EdgeInterRobot(0, random.choice(range(nb_poses)), 0,
194  random.choice(range(nb_poses)), 1.0))
195  selection1 = ac.select_candidates(nb_candidates_to_choose,
196  is_robot_considered,
197  greedy_initialization=False)
198  self.assertEqual(len(selection1), nb_candidates_to_choose)
199 
201  """Test that we can remove candidates from consideration
202  """
203  # Build simple graph
204  nb_poses = 100
205  nb_candidate_edges = 50
206  nb_candidates_to_choose = 10
207  fixed_edges_list, candidate_edges_list = build_simple_graph(
208  nb_poses, nb_candidate_edges)
210  ac.set_graph(fixed_edges_list, candidate_edges_list)
211 
212  # Solve the initial graph
213  candidates_edges_before = ac.candidate_edges.copy()
214  is_robot_considered = {0: True}
215  selection0 = ac.select_candidates(nb_candidates_to_choose,
216  is_robot_considered,
217  greedy_initialization=False)
218  self.assertEqual(len(selection0), nb_candidates_to_choose)
219 
220  test = set()
221  for e in selection0:
222  self.assertIn(e, list(candidates_edges_before.values()))
223  test.add(e)
224  # Check that there are no duplicates
225  self.assertEqual(len(test), nb_candidates_to_choose)
226 
227  nb_candidates0 = len(ac.candidate_edges)
228 
229  # Remove edges
230  ac.remove_candidate_edges(list(ac.candidate_edges.values())[:nb_candidates_to_choose])
231  nb_candidates1 = len(ac.candidate_edges)
232  self.assertGreaterEqual(nb_candidates0,
233  nb_candidates1 + nb_candidates_to_choose - 1)
234  self.assertLessEqual(nb_candidates0,
235  nb_candidates1 + nb_candidates_to_choose + 1)
236 
238  """Test that we can remove candidates from consideration
239  """
240  # Build graph
241  robot_id = 0
242  nb_poses = 10
243  nb_candidate_edges = 10
244  max_nb_robots = 3
245  nb_candidates_to_choose = 3
246  fixed_edges_list, candidate_edges_list = build_multi_robot_graph(
247  nb_poses, nb_candidate_edges, max_nb_robots)
248 
249  ac = AlgebraicConnectivityMaximization(robot_id=robot_id,
250  max_nb_robots=max_nb_robots)
251  ac.set_graph(fixed_edges_list, candidate_edges_list)
252  candidates_edges_before = ac.candidate_edges.copy()
253 
254  # Solve the initial graph
255  is_robot_considered = {}
256  for i in range(max_nb_robots):
257  is_robot_considered[i] = True
258  selection0 = ac.select_candidates(nb_candidates_to_choose,
259  is_robot_considered,
260  greedy_initialization=False)
261  self.assertEqual(len(selection0), nb_candidates_to_choose)
262 
263  for e in selection0:
264  self.assertIn(e, list(candidates_edges_before.values()))
265 
266  nb_candidates0 = len(ac.candidate_edges)
267 
268  # Remove edges
269  existant_edge = [list(ac.candidate_edges.values())[0]]
270  inexistant_edge = [EdgeInterRobot(0, 1, 4, 1, 1.0)]
271  ac.remove_candidate_edges(existant_edge)
272  nb_candidates1 = len(ac.candidate_edges)
273  self.assertEqual(nb_candidates0, nb_candidates1 + 1)
274 
275  ac.remove_candidate_edges(inexistant_edge)
276  nb_candidates2 = len(ac.candidate_edges)
277  self.assertEqual(nb_candidates0, nb_candidates2 + 1)
278 
280  """Test that we can declare candidate fixed if they are successfully
281  computed
282  """
283  # Build simple graph
284  nb_poses = 100
285  nb_candidate_edges = 50
286  nb_candidates_to_choose = 10
287  fixed_edges_list, candidate_edges_list = build_simple_graph(
288  nb_poses, nb_candidate_edges)
290  ac.set_graph(fixed_edges_list, candidate_edges_list)
291 
292  candidates_edges_before = ac.candidate_edges.copy()
293 
294  # Solve the initial graph
295  is_robot_considered = {0: True}
296  selection0 = ac.select_candidates(nb_candidates_to_choose,
297  is_robot_considered,
298  greedy_initialization=False)
299  self.assertEqual(len(selection0), nb_candidates_to_choose)
300 
301  for e in selection0:
302  self.assertIn(e, list(candidates_edges_before.values()))
303 
304  # Swap edge, make sure that none are the same
305  ac.candidate_edges_to_fixed(selection0)
306  for e in selection0:
307  self.assertNotIn(e, list(ac.candidate_edges.values()))
308 
309  selection1 = ac.select_candidates(nb_candidates_to_choose,
310  is_robot_considered,
311  greedy_initialization=False)
312 
313  for e in selection1:
314  self.assertIn(e, list(candidates_edges_before.values()))
315 
316  for e0 in selection0:
317  for e1 in selection1:
318  self.assertFalse(e0.robot0_keyframe_id == e1.robot0_keyframe_id
319  and e0.robot1_keyframe_id == e1.robot1_keyframe_id)
320 
322  """Test connectivity check
323  """
324  # All robots connected
325  robot_id = 0
326  nb_poses = 10
327  nb_candidate_edges = 10
328  max_nb_robots = 3
329  is_robot_considered = {}
330  for i in range(max_nb_robots):
331  is_robot_considered[i] = True
332 
333  fixed_edges_list, candidate_edges_list = build_multi_robot_graph(
334  nb_poses, nb_candidate_edges, max_nb_robots)
335 
336  ac = AlgebraicConnectivityMaximization(robot_id=robot_id,
337  max_nb_robots=max_nb_robots)
338  ac.set_graph(fixed_edges_list, candidate_edges_list)
339 
340  is_robot_included = ac.check_graph_disconnections(is_robot_considered)
341 
342  for r in is_robot_included:
343  self.assertTrue(is_robot_included[r])
344 
345  is_robot_considered[1] = False
346 
347  is_robot_included = ac.check_graph_disconnections(is_robot_considered)
348  for r in is_robot_included:
349  if is_robot_considered[r]:
350  self.assertTrue(is_robot_included[r])
351  else:
352  self.assertFalse(is_robot_included[r])
353 
354  is_robot_considered[1] = True
355 
356  # Robot 0 not connected
357  robot_id = 1
358  nb_poses = 10
359  nb_candidate_edges = 10
360  max_nb_robots = 3
361  fixed_edges_list, candidate_edges_list = build_multi_robot_graph(
362  nb_poses, nb_candidate_edges, max_nb_robots)
363 
364  to_delete = []
365  for i in range(len(fixed_edges_list)):
366  if fixed_edges_list[i].robot0_id == 0 or fixed_edges_list[
367  i].robot1_id == 0:
368  to_delete.append(fixed_edges_list[i])
369  for e in to_delete:
370  fixed_edges_list.remove(e)
371 
372  to_delete = []
373  for i in range(len(candidate_edges_list)):
374  if candidate_edges_list[i].robot0_id == 0 or candidate_edges_list[
375  i].robot1_id == 0:
376  to_delete.append(candidate_edges_list[i])
377  for e in to_delete:
378  candidate_edges_list.remove(e)
379 
380  ac = AlgebraicConnectivityMaximization(robot_id=robot_id,
381  max_nb_robots=max_nb_robots)
382  ac.set_graph(fixed_edges_list, candidate_edges_list)
383 
384  is_robot_included = ac.check_graph_disconnections(is_robot_considered)
385 
386  for r in is_robot_included:
387  if r == 0:
388  self.assertFalse(is_robot_included[r])
389  else:
390  self.assertTrue(is_robot_included[r])
391 
393  """Test connectivity check
394  """
395  # All robots connected
396  robot_id = 1
397  nb_poses = 10
398  nb_candidate_edges = 10
399  max_nb_robots = 5
400  fixed_edges_list, candidate_edges_list = build_multi_robot_graph(
401  nb_poses, nb_candidate_edges, max_nb_robots)
402 
403  ac = AlgebraicConnectivityMaximization(robot_id=robot_id,
404  max_nb_robots=max_nb_robots)
405  ac.set_graph(fixed_edges_list, candidate_edges_list)
406 
407  is_robot_considered = {}
408  for i in range(max_nb_robots):
409  is_robot_considered[i] = True
410  is_robot_included = ac.check_graph_disconnections(is_robot_considered)
411  ac.compute_offsets(is_robot_included)
412 
413  nb_poses = ac.nb_poses
414  self.assertEqual(ac.offsets[0], 0)
415  self.assertEqual(ac.offsets[1], ac.offsets[0] + nb_poses[0])
416  self.assertEqual(ac.offsets[2], ac.offsets[1] + nb_poses[1])
417  self.assertEqual(ac.offsets[3], ac.offsets[2] + nb_poses[2])
418  self.assertEqual(ac.offsets[4], ac.offsets[3] + nb_poses[3])
419 
420  # Robot 0 not connected
421  to_delete = []
422  for i in range(len(fixed_edges_list)):
423  if fixed_edges_list[i].robot0_id == 0 or fixed_edges_list[
424  i].robot1_id == 0:
425  to_delete.append(fixed_edges_list[i])
426  for e in to_delete:
427  fixed_edges_list.remove(e)
428 
429  to_delete = []
430  for i in range(len(candidate_edges_list)):
431  if candidate_edges_list[i].robot0_id == 0 or candidate_edges_list[
432  i].robot1_id == 0:
433  to_delete.append(candidate_edges_list[i])
434  for e in to_delete:
435  candidate_edges_list.remove(e)
436 
437  ac = AlgebraicConnectivityMaximization(robot_id=robot_id,
438  max_nb_robots=max_nb_robots)
439  ac.set_graph(fixed_edges_list, candidate_edges_list)
440 
441  is_robot_included = ac.check_graph_disconnections(is_robot_considered)
442  ac.compute_offsets(is_robot_included)
443 
444  self.assertEqual(ac.offsets[0], 0)
445  self.assertEqual(ac.offsets[1], 0)
446  self.assertEqual(ac.offsets[2], ac.offsets[1] + nb_poses[1])
447  self.assertEqual(ac.offsets[3], ac.offsets[2] + nb_poses[2])
448  self.assertEqual(ac.offsets[4], ac.offsets[3] + nb_poses[3])
449 
450  # Robot 0 and 3 not connected
451  to_delete = []
452  for i in range(len(fixed_edges_list)):
453  if fixed_edges_list[i].robot0_id == 3 or fixed_edges_list[
454  i].robot1_id == 3:
455  to_delete.append(fixed_edges_list[i])
456  for e in to_delete:
457  fixed_edges_list.remove(e)
458 
459  to_delete = []
460  for i in range(len(candidate_edges_list)):
461  if candidate_edges_list[i].robot0_id == 3 or candidate_edges_list[
462  i].robot1_id == 3:
463  to_delete.append(candidate_edges_list[i])
464  for e in to_delete:
465  candidate_edges_list.remove(e)
466 
467  # Ensure connectivity
468  edge = EdgeInterRobot(1, 1, 4, 1, 1.0)
469  fixed_edges_list.append(edge)
470 
471  ac = AlgebraicConnectivityMaximization(robot_id=robot_id,
472  max_nb_robots=max_nb_robots)
473  ac.set_graph(fixed_edges_list, candidate_edges_list)
474 
475  is_robot_included = ac.check_graph_disconnections(is_robot_considered)
476  ac.compute_offsets(is_robot_included)
477 
478  self.assertEqual(ac.offsets[0], 0)
479  self.assertEqual(ac.offsets[1], 0)
480  self.assertEqual(ac.offsets[2], ac.offsets[1] + nb_poses[1])
481  self.assertEqual(ac.offsets[3], 0)
482  self.assertEqual(ac.offsets[4], ac.offsets[2] + nb_poses[2])
483 
484  def test_keys(self):
485  """Test key changes between C-SLAM system and solver
486  """
487  robot_id = 0
488  nb_poses = 10
489  nb_candidate_edges = 10
490  max_nb_robots = 3
491  fixed_edges_list, candidate_edges_list = build_multi_robot_graph(
492  nb_poses, nb_candidate_edges, max_nb_robots)
493 
494  ac = AlgebraicConnectivityMaximization(robot_id=robot_id,
495  max_nb_robots=max_nb_robots)
496  ac.set_graph(fixed_edges_list, candidate_edges_list)
497 
498  is_robot_considered = {}
499  for i in range(max_nb_robots):
500  is_robot_considered[i] = True
501  is_robot_included = ac.check_graph_disconnections(is_robot_considered)
502 
503  ac.compute_offsets(is_robot_included)
504  rekeyed_fixed_edges = ac.rekey_edges(ac.fixed_edges, is_robot_included)
505  self.assertEqual(len(ac.fixed_edges), 2)
506  rekeyed_fixed_edges.extend(ac.fill_odometry())
507  self.assertEqual(len(rekeyed_fixed_edges),
508  max_nb_robots * (nb_poses - 1) + 2)
509  rekeyed_candidate_edges = ac.rekey_edges(ac.candidate_edges.values(),
510  is_robot_included)
511  values = list(ac.candidate_edges.values())
512  for i in range(len(values)):
513  e = values[i]
514  r = rekeyed_candidate_edges[i]
515  self.assertEqual(r.i, e.robot0_keyframe_id + e.robot0_id * 10)
516  self.assertEqual(r.j, e.robot1_keyframe_id + e.robot1_id * 10)
517 
518  recovered_edges = ac.recover_inter_robot_edges(rekeyed_candidate_edges,
519  is_robot_included)
520  for i in range(len(values)):
521  e = values[i]
522  r = recovered_edges[i]
523  self.assertEqual(r.robot0_keyframe_id, e.robot0_keyframe_id)
524  self.assertEqual(r.robot1_keyframe_id, e.robot1_keyframe_id)
525 
527  """Test graph with multi-robot edges
528  """
529  robot_id = 0
530 
531  nb_poses = 100
532  nb_candidate_edges = 100
533  max_nb_robots = 3
534  nb_candidates_to_choose = 10
535  fixed_edges_list, candidate_edges_list = build_multi_robot_graph(
536  nb_poses, nb_candidate_edges, max_nb_robots)
537 
538  ac = AlgebraicConnectivityMaximization(robot_id=robot_id,
539  max_nb_robots=max_nb_robots)
540  ac.set_graph(fixed_edges_list, candidate_edges_list)
541 
542  is_robot_considered = {}
543  for i in range(max_nb_robots):
544  is_robot_considered[i] = True
545 
546  # Solve the graph
547  selection = ac.select_candidates(nb_candidates_to_choose,
548  is_robot_considered,
549  greedy_initialization=False)
550  self.assertEqual(len(selection), nb_candidates_to_choose)
551  for s in selection:
552  self.assertLess(s.robot0_keyframe_id, nb_poses)
553  self.assertGreaterEqual(s.robot0_keyframe_id, 0)
554  self.assertLess(s.robot1_keyframe_id, nb_poses)
555  self.assertGreaterEqual(s.robot0_keyframe_id, 0)
556  self.assertGreaterEqual(s.robot0_id, 0)
557  self.assertGreaterEqual(s.robot1_id, 0)
558  self.assertLess(s.robot0_id, max_nb_robots)
559  self.assertLess(s.robot1_id, max_nb_robots)
560 
562  """Test graph with multi-robot edges
563  """
564  robot_id = 1
565 
566  nb_poses = 100
567  nb_candidate_edges = 100
568  max_nb_robots = 3
569  nb_candidates_to_choose = 10
570  fixed_edges_list, candidate_edges_list = build_multi_robot_graph(
571  nb_poses, nb_candidate_edges, max_nb_robots)
572 
573  ac = AlgebraicConnectivityMaximization(robot_id=robot_id,
574  max_nb_robots=max_nb_robots)
575  ac.set_graph(fixed_edges_list, candidate_edges_list)
576 
577  is_robot_considered = {}
578  for i in range(max_nb_robots):
579  is_robot_considered[i] = True
580 
581  # Solve the graph
582  selection = ac.select_candidates(nb_candidates_to_choose,
583  is_robot_considered,
584  greedy_initialization=False)
585  self.assertEqual(len(selection), nb_candidates_to_choose)
586 
587  def test_add_match(self):
588  """Test add match
589  """
590  robot_id = 0
591  max_nb_robots = 3
592 
593  ac = AlgebraicConnectivityMaximization(robot_id=robot_id,
594  max_nb_robots=max_nb_robots)
595 
596  e0 = EdgeInterRobot(0, 1, 1, 3, 0.1)
597  ac.add_match(e0)
598  self.assertEqual(len(ac.candidate_edges.values()), 1)
599  e1 = EdgeInterRobot(0, 2, 2, 4, 0.1)
600  ac.add_match(e1)
601  self.assertEqual(len(ac.candidate_edges.values()), 2)
602  e2 = EdgeInterRobot(0, 1, 1, 3, 0.2)
603  ac.add_match(e2)
604  self.assertEqual(len(ac.candidate_edges.values()), 2)
605  self.assertAlmostEqual(
606  ac.candidate_edges[(e2.robot0_id, e2.robot0_keyframe_id, e2.robot1_id,
607  e2.robot1_keyframe_id)].weight, 0.2)
608 
609 
610 if __name__ == "__main__":
611  unittest.main()
def build_multi_robot_graph(nb_poses, nb_candidate_edges, max_nb_robots)
def build_simple_graph(nb_poses, nb_candidate_edges)