@@ -26,6 +26,74 @@ class OptimizationTarget(enum.IntEnum):
2626 LowLID = deglib_cpp .OptimizationTarget .LowLID
2727
2828
29+ class BuilderStatus :
30+ """
31+ Snapshot of the graph build progress.
32+
33+ Instances are created internally and passed to the ``callback`` of
34+ :meth:`GraphBuilder.build`, and returned by :meth:`GraphBuilder.build`.
35+ This facade wraps the native status object so that end users never have to
36+ interact with the ``deglib_cpp`` bindings directly.
37+
38+ The instance handed to a progress ``callback`` is only valid for the
39+ duration of that callback invocation.
40+ """
41+
42+ def __init__ (self , status_cpp : deglib_cpp .BuilderStatus ):
43+ self ._status_cpp = status_cpp
44+
45+ @property
46+ def step (self ) -> int :
47+ """Number of graph manipulation steps completed."""
48+ return self ._status_cpp .step
49+
50+ @property
51+ def added (self ) -> int :
52+ """Total number of vertices added so far."""
53+ return self ._status_cpp .added
54+
55+ @property
56+ def deleted (self ) -> int :
57+ """Total number of vertices deleted so far."""
58+ return self ._status_cpp .deleted
59+
60+ @property
61+ def improved (self ) -> int :
62+ """Total number of successful edge improvements so far."""
63+ return self ._status_cpp .improved
64+
65+ @property
66+ def tries (self ) -> int :
67+ """Total number of improvement attempts so far."""
68+ return self ._status_cpp .tries
69+
70+ @property
71+ def step_added_ids (self ):
72+ """External labels added during the current build step."""
73+ return self ._status_cpp .step_added_ids
74+
75+ @property
76+ def step_deleted_ids (self ):
77+ """External labels deleted during the current build step."""
78+ return self ._status_cpp .step_deleted_ids
79+
80+ @property
81+ def total_added_ids (self ):
82+ """All external labels added across the entire build."""
83+ return self ._status_cpp .total_added_ids
84+
85+ @property
86+ def total_deleted_ids (self ):
87+ """All external labels deleted across the entire build."""
88+ return self ._status_cpp .total_deleted_ids
89+
90+ def __repr__ (self ) -> str :
91+ return (
92+ f"BuilderStatus(step={ self .step } , added={ self .added } , deleted={ self .deleted } , "
93+ f"improved={ self .improved } , tries={ self .tries } )"
94+ )
95+
96+
2997class GraphBuilder :
3098 """
3199 Constructs a GraphBuilder for building and optimizing a regular graph.
@@ -186,26 +254,33 @@ def get_batch_size(self) -> int:
186254 return self .builder_cpp .get_batch_size ()
187255
188256 def build (
189- self , callback : Callable [[deglib_cpp .BuilderStatus ], None ] | str | None = None , infinite : bool = False
190- ) -> deglib_cpp .BuilderStatus :
257+ self ,
258+ callback : Callable [[BuilderStatus ], None ] | None = None ,
259+ show_progress : bool = False ,
260+ infinite : bool = False ,
261+ ) -> BuilderStatus :
191262 """
192263 Build the graph. This could be run on a separate thread in an infinite loop. Call stop() to end this process.
193264
194265 :param callback: The callback that is called after each step of the build process. A BuilderStatus
195- is the only argument to the function.
196- If None nothing is printed.
197- If callback is the string "progress", a simple progress bar is printed to stdout .
266+ is the only argument to the function. If None nothing is printed.
267+ :param show_progress: If True and no callback is given, a simple progress bar is printed to stdout .
268+ Ignored when running in infinite mode (total workload is unknown) .
198269 :param infinite: If set to True, blocks indefinitely, until the stop() function is called. Can be used, if
199270 build() is run in a separate thread.
200271 :return: BuilderStatus containing build metrics and ID vectors for added/deleted vertices.
201- :rtype: deglib_cpp. BuilderStatus
272+ :rtype: BuilderStatus
202273 """
274+ if callback is None and show_progress and not infinite :
275+ callback = ProgressCallback (self .get_num_new_entries (), self .get_num_remove_entries ())
276+
203277 if callback is None :
204- return self .builder_cpp .build_silent (infinite )
205- else :
206- if not infinite and callback == "progress" :
207- callback = ProgressCallback (self .get_num_new_entries (), self .get_num_remove_entries ())
208- return self .builder_cpp .build (callback , infinite )
278+ return BuilderStatus (self .builder_cpp .build_silent (infinite ))
279+
280+ def _callback (status_cpp ) -> None :
281+ callback (BuilderStatus (status_cpp ))
282+
283+ return BuilderStatus (self .builder_cpp .build (_callback , infinite ))
209284
210285 def stop (self ):
211286 """
@@ -241,7 +316,8 @@ def build_from_data(
241316 max_path_length : int = 5 ,
242317 improve_tries : int = 0 ,
243318 thread_count : int = 0 ,
244- callback : Callable [[deglib_cpp .BuilderStatus ], None ] | str | None = None ,
319+ callback : Callable [[BuilderStatus ], None ] | None = None ,
320+ show_progress : bool = False ,
245321) -> DynamicExplorationGraph :
246322 """
247323 Create a new graph built from the given data using a GraphBuilder.
@@ -282,8 +358,10 @@ def build_from_data(
282358 :type improve_tries: int
283359 :param thread_count: Number of threads to use for parallel building. If 0, uses hardware concurrency.
284360 :type thread_count: int
285- :param callback: Callback function for build progress reporting. If "progress", shows progress bar
286- :type callback: Callable[[deglib_cpp.BuilderStatus], None] | str | None
361+ :param callback: Callback function for build progress reporting, receiving a BuilderStatus. If None, nothing is reported.
362+ :type callback: Callable[[BuilderStatus], None] | None
363+ :param show_progress: If True and no callback is given, a simple progress bar is printed to stdout.
364+ :type show_progress: bool
287365 :return: The constructed and optimized graph
288366 :rtype: DynamicExplorationGraph
289367 """
@@ -311,7 +389,7 @@ def build_from_data(
311389 if thread_count > 0 :
312390 builder .set_thread_count (thread_count )
313391
314- builder .build (callback = callback )
392+ builder .build (callback = callback , show_progress = show_progress )
315393
316394 return graph
317395
@@ -347,15 +425,15 @@ def __init__(
347425 self .last_print_time = 0
348426 self .min_print_interval = min_print_interval
349427
350- def __call__ (self , builder_status : deglib_cpp . BuilderStatus ):
428+ def __call__ (self , builder_status : BuilderStatus ):
351429 """
352430 Display the current build progress as a formatted progress bar.
353431
354432 Called by the builder during the build process to report status. Updates are throttled
355433 by min_print_interval to avoid excessive output, except for the final step.
356434
357435 :param builder_status: Current status of the build process containing step counts
358- :type builder_status: deglib_cpp. BuilderStatus
436+ :type builder_status: BuilderStatus
359437 """
360438 current_time = time .time ()
361439 num_steps = builder_status .added + builder_status .deleted
0 commit comments