← Documentation
ADS-IDAC Engine 5.0.0
workspace.hpp
Go to the documentation of this file.
1#pragma once
13#include <unordered_map>
14#include <vector>
15
16namespace bncore {
17
18// ---------------------------------------------------------------------------
19// Pre-baked collect/distribute op for a single tree edge (child u → parent p).
20// All index maps are computed once at construction; calibrate() does only
21// table reads with zero heap allocation in the hot path.
22// ---------------------------------------------------------------------------
32struct CollectOp {
33 std::size_t product_states;
34 std::vector<uint32_t> pot_map;
35 std::vector<std::vector<uint32_t>> child_maps;
36 std::vector<std::size_t> child_cliques;
37 std::vector<uint32_t> marg_map;
38};
39
48 std::size_t product_states;
49 std::vector<uint32_t> pot_map;
50 bool has_parent_down = false;
51 std::vector<uint32_t> down_map;
52 std::vector<std::vector<uint32_t>> sibling_maps;
53 std::vector<std::size_t> sibling_cliques;
54 std::vector<uint32_t> marg_map;
55 std::size_t parent_clique = 0;
56};
57
62struct AssembleOp {
63 std::size_t product_states;
64 bool has_down = false;
65 std::vector<uint32_t> down_map;
66 std::vector<std::vector<uint32_t>> child_maps;
67 std::vector<std::size_t> child_cliques;
68};
69
70// ---------------------------------------------------------------------------
71// Pre-baked per-variable marginalisation map for fast query extraction.
72// ---------------------------------------------------------------------------
84 std::vector<std::vector<uint8_t>> state_of_dim;
85 std::size_t n_states_total = 0;
86};
87
111public:
123 explicit BatchWorkspace(const JunctionTree &jt, std::size_t batch_size = 1);
124
143 void reset(std::size_t new_batch_size, std::size_t cpt_batch_offset = 0);
144
145 // ---------------------------------------------------------------------------
146 // Hard evidence
147 // ---------------------------------------------------------------------------
159 void set_evidence_matrix(const int *evidence_matrix, std::size_t num_vars);
161 void clear_evidence();
162
163 // ---------------------------------------------------------------------------
164 // Soft / virtual evidence
165 //
166 // set_soft_evidence: supply a likelihood vector lambda[0..n_states-1] for a
167 // single variable. lambda[s] = P(measurement | X=s). Hard evidence state s0
168 // is a special case: lambda[s0]=1, all others 0.
169 //
170 // n_states must match the variable's cardinality; throws otherwise.
171 // Likelihoods need not sum to one (improper likelihoods are valid).
172 // Likelihoods must be non-negative; throws on negative entries.
173 // ---------------------------------------------------------------------------
188 void set_soft_evidence(NodeId var, const double *likelihoods,
189 std::size_t n_states);
203 void set_soft_evidence_matrix(NodeId var, const double *likelihoods_matrix,
204 std::size_t n_states);
206 void clear_soft_evidence();
207
208 // ---------------------------------------------------------------------------
209 // Sum-product calibration (standard marginal inference)
210 // ---------------------------------------------------------------------------
227 void calibrate();
228
229 // ---------------------------------------------------------------------------
230 // Max-product calibration (MAP / MPE inference)
231 //
232 // After max_calibrate(), call query_map() to decode the joint MAP assignment.
233 // ---------------------------------------------------------------------------
246 void max_calibrate();
247
259 void query_map(int *out_states, std::size_t n_vars) const;
260
261 // ---------------------------------------------------------------------------
262 // Query extraction (sum-product results)
263 // ---------------------------------------------------------------------------
264
272
288 void query_marginals_multi(const NodeId *query_vars, std::size_t num_queries,
289 const std::size_t *offsets,
290 double *out) const;
291
292private:
295 void rebuild_clique_potentials(std::size_t target_batch_size);
297 void resize_runtime_buffers(std::size_t target_batch_size);
303
304 // Internal helpers
305 // apply_soft_evidence_to_clique: applies stored soft/hard likelihood vectors
306 // to a single clique potential. Used by both calibrate() paths.
307 // Returns true if any likelihood was applied to this clique.
308 bool apply_soft_evidence_to_clique(std::size_t ci);
309
311 std::size_t batch_size_;
312 std::size_t cpt_batch_offset_ = 0;
313
314 std::vector<Factor> clique_potentials_;
315 std::vector<Factor> base_clique_potentials_;
316 std::size_t base_batch_size_ = 0;
317 std::size_t base_batch_offset_ = 0;
319 const int *evidence_matrix_ = nullptr;
320 std::size_t evidence_num_vars_ = 0;
321
322 // Soft evidence storage:
323 // soft_evidence_scalar_[var] = likelihood vector for B=1 or shared across B
324 // soft_evidence_matrix_[var] = per-row likelihood matrix [B * n_states]
325 // (populated by set_soft_evidence_matrix)
326 std::unordered_map<NodeId, std::vector<double>> soft_evidence_scalar_;
327 std::unordered_map<NodeId, std::vector<double>> soft_evidence_matrix_;
328
329 std::size_t root_clique_;
330 std::vector<std::size_t> collect_order_;
331 std::vector<std::size_t> distribute_order_;
332 std::vector<std::size_t> parent_of_;
333 std::vector<std::vector<std::size_t>> children_of_;
334
335 // Pre-baked zero-allocation message schedule
336 std::vector<std::vector<double>> up_msg_buf_;
337 std::vector<std::vector<double>> down_msg_buf_;
338 std::vector<std::size_t> up_msg_size_;
339 std::vector<std::size_t> down_msg_size_;
340 std::vector<std::size_t> sepset_size_;
341 std::vector<std::size_t> clique_states_;
342
343 std::vector<CollectOp> collect_ops_;
344 std::vector<DistributeOp> distribute_ops_;
345 std::vector<AssembleOp> assemble_ops_;
346
347 // P1: Persistent scratch buffer, sized to max product_states at construction,
348 // then resized as max_product_states * batch_size for runtime chunk geometry.
349 // Reused every calibrate() with zero heap allocation in the hot path.
350 std::vector<double> scratch_buf_;
351 std::size_t max_product_states_ = 0;
352
353 // Phase-A: workspace-owned uint8_t scratch flags, pre-sized at construction,
354 // cleared via memset at top of calibrate() with ZERO heap allocation.
355 // Using uint8_t instead of vector<bool>: byte-addressable, not bit-packed.
356 std::vector<uint8_t> ev_clique_; // did evidence touch this clique?
357 std::vector<uint8_t> up_changed_; // did up_msg change in collect?
358 std::vector<uint8_t> down_changed_; // did down_msg change in distribute?
359 std::vector<uint8_t> cal_changed_; // does assembled cal_pot need update?
360
361 // Calibrated potentials (sum-product)
362 std::vector<std::vector<double>> cal_pot_buf_;
363 std::vector<std::size_t> cal_pot_size_;
364
365 // Max-product message buffers and traceback (MAP inference)
366 // Layout mirrors up_msg_buf_: [sepset_size * B]
367 std::vector<std::vector<double>> map_up_msg_buf_;
368 // map_traceback_[clique][product_state] = which child-combined input index
369 // achieved the max; used by query_map() to decode argmax state per variable.
370 std::vector<std::vector<uint32_t>> map_traceback_;
371 // Calibrated max-product beliefs per clique (assembled after max_calibrate)
372 std::vector<std::vector<double>> map_cal_pot_buf_;
373
374 // Base (no-evidence) caches for lazy propagation
375 std::vector<std::vector<double>> base_up_buf_;
376 std::vector<std::vector<double>> base_down_buf_;
377 std::vector<std::vector<double>> base_cal_buf_;
379
380 // P2: Pre-baked per-clique per-variable marginalisation maps
381 std::vector<CliqueMargInfo> clique_marg_info_;
382
383 // P3: Per-clique evidence scratch buffers (replaces fixed-size BumpAllocator)
384 // ev_scratch_[ci] is lazily sized to clique_states_[ci] on first evidence use.
385 std::vector<std::vector<double>> ev_scratch_;
386 // Tracks which clique entries are owned by ev_scratch_ (not base potentials)
387 std::vector<bool> ev_scratch_active_;
388
389 // O(1) lookups
390 std::unordered_map<NodeId, std::size_t> node_to_clique_;
391 std::unordered_map<NodeId, std::vector<std::size_t>> node_in_cliques_;
392
393 // Query-time scratch for safe fallback when clique count exceeds stack guard.
394 mutable std::vector<uint8_t> query_visited_scratch_;
395};
396
397} // namespace bncore
Message passing state for one junction tree and one batch size.
Definition: workspace.hpp:110
std::vector< std::size_t > down_msg_size_
Definition: workspace.hpp:339
std::size_t batch_size_
Definition: workspace.hpp:311
std::unordered_map< NodeId, std::vector< double > > soft_evidence_matrix_
Definition: workspace.hpp:327
void build_message_schedule()
Fills collect_ops_, distribute_ops_, assemble_ops_ and clique_marg_info_.
Definition: workspace.cpp:141
std::vector< std::size_t > collect_order_
Definition: workspace.hpp:330
std::vector< std::size_t > sepset_size_
Definition: workspace.hpp:340
std::vector< std::vector< uint32_t > > map_traceback_
Definition: workspace.hpp:370
std::vector< std::size_t > cal_pot_size_
Definition: workspace.hpp:363
std::vector< uint8_t > cal_changed_
Definition: workspace.hpp:359
std::unordered_map< NodeId, std::vector< double > > soft_evidence_scalar_
Definition: workspace.hpp:326
const int * evidence_matrix_
Definition: workspace.hpp:319
void clear_soft_evidence()
Removes all soft evidence, scalar and matrix.
Definition: workspace.cpp:552
std::size_t root_clique_
Definition: workspace.hpp:329
std::vector< std::vector< double > > map_cal_pot_buf_
Definition: workspace.hpp:372
void set_soft_evidence_matrix(NodeId var, const double *likelihoods_matrix, std::size_t n_states)
Sets a separate likelihood vector per batch row for a variable.
Definition: workspace.cpp:532
DenseTensor query_marginal(NodeId node) const
Marginal of one variable from the last calibrate().
Definition: workspace.cpp:1135
void calibrate()
Runs sum-product message passing with the current evidence.
Definition: workspace.cpp:682
std::unordered_map< NodeId, std::size_t > node_to_clique_
Definition: workspace.hpp:390
std::vector< std::vector< double > > base_up_buf_
Definition: workspace.hpp:375
std::vector< std::vector< double > > ev_scratch_
Definition: workspace.hpp:385
std::vector< uint8_t > query_visited_scratch_
Definition: workspace.hpp:394
std::vector< Factor > clique_potentials_
Definition: workspace.hpp:314
bool apply_soft_evidence_to_clique(std::size_t ci)
Definition: workspace.cpp:573
void clear_evidence()
Forgets the hard evidence matrix. Soft evidence is not affected.
Definition: workspace.cpp:507
std::vector< std::vector< double > > map_up_msg_buf_
Definition: workspace.hpp:367
std::vector< std::vector< double > > up_msg_buf_
Definition: workspace.hpp:336
std::size_t base_batch_size_
Definition: workspace.hpp:316
std::vector< bool > ev_scratch_active_
Definition: workspace.hpp:387
std::vector< std::vector< double > > base_cal_buf_
Definition: workspace.hpp:377
const JunctionTree & jt_
Definition: workspace.hpp:310
std::vector< std::vector< double > > cal_pot_buf_
Definition: workspace.hpp:362
std::vector< CollectOp > collect_ops_
Definition: workspace.hpp:343
std::unordered_map< NodeId, std::vector< std::size_t > > node_in_cliques_
Definition: workspace.hpp:391
BatchWorkspace(const JunctionTree &jt, std::size_t batch_size=1)
Builds the workspace and calibrates it without evidence.
Definition: workspace.cpp:89
std::vector< std::vector< double > > base_down_buf_
Definition: workspace.hpp:376
void resize_runtime_buffers(std::size_t target_batch_size)
Sizes message, belief and scratch buffers for a batch size.
Definition: workspace.cpp:322
std::vector< std::size_t > distribute_order_
Definition: workspace.hpp:331
std::size_t evidence_num_vars_
Definition: workspace.hpp:320
std::vector< AssembleOp > assemble_ops_
Definition: workspace.hpp:345
std::vector< std::vector< std::size_t > > children_of_
Definition: workspace.hpp:333
void max_calibrate()
Runs max-product propagation with the current evidence, for query_map().
Definition: workspace.cpp:1160
void set_soft_evidence(NodeId var, const double *likelihoods, std::size_t n_states)
Sets one likelihood vector for a variable, shared by all batch rows.
Definition: workspace.cpp:514
std::vector< std::size_t > clique_states_
Definition: workspace.hpp:341
std::vector< DistributeOp > distribute_ops_
Definition: workspace.hpp:344
void snapshot_base_potentials()
Copies clique_potentials_ into owning base_clique_potentials_.
Definition: workspace.cpp:360
std::vector< uint8_t > up_changed_
Definition: workspace.hpp:357
std::size_t base_batch_offset_
Definition: workspace.hpp:317
void set_evidence_matrix(const int *evidence_matrix, std::size_t num_vars)
Sets the hard evidence for the next calibration.
Definition: workspace.cpp:504
std::vector< double > scratch_buf_
Definition: workspace.hpp:350
void query_marginals_multi(const NodeId *query_vars, std::size_t num_queries, const std::size_t *offsets, double *out) const
Marginals of several variables from the last calibrate(), with one scan of each clique involved.
Definition: workspace.cpp:987
std::vector< std::vector< double > > down_msg_buf_
Definition: workspace.hpp:337
std::vector< CliqueMargInfo > clique_marg_info_
Definition: workspace.hpp:381
std::size_t max_product_states_
Definition: workspace.hpp:351
std::vector< std::size_t > up_msg_size_
Definition: workspace.hpp:338
std::vector< std::size_t > parent_of_
Definition: workspace.hpp:332
std::vector< uint8_t > ev_clique_
Definition: workspace.hpp:356
void reset(std::size_t new_batch_size, std::size_t cpt_batch_offset=0)
Prepares the workspace for a new evidence case.
Definition: workspace.cpp:475
std::size_t cpt_batch_offset_
Definition: workspace.hpp:312
std::vector< Factor > base_clique_potentials_
Definition: workspace.hpp:315
std::vector< uint8_t > down_changed_
Definition: workspace.hpp:358
void rebuild_clique_potentials(std::size_t target_batch_size)
Definition: workspace.cpp:371
void query_map(int *out_states, std::size_t n_vars) const
Decodes a state for each variable from the max-product beliefs.
Definition: workspace.cpp:1257
Dense row-major array of doubles with a fixed shape.
Cliques and separators compiled from one Graph.
bncore::Factor, a table of doubles over a list of variables, with the product and sum-out operations ...
Junction tree data structure of BNCore: Clique, Separator and the JunctionTree container.
std::uint32_t NodeId
Handle of a variable within one Graph.
Definition: node.hpp:20
Index tables that assemble the calibrated belief of one clique from its potential,...
Definition: workspace.hpp:62
std::vector< uint32_t > down_map
[clique_idx] to index in the clique's down message; empty unless has_down
Definition: workspace.hpp:65
std::size_t product_states
number of states of the clique
Definition: workspace.hpp:63
std::vector< std::vector< uint32_t > > child_maps
[child_i][clique_idx] to index in that child's up message
Definition: workspace.hpp:66
std::vector< std::size_t > child_cliques
clique indices of the children, parallel to child_maps
Definition: workspace.hpp:67
bool has_down
true when the clique has a parent
Definition: workspace.hpp:64
Per-clique lookup from a flat clique index to the state of each scope variable.
Definition: workspace.hpp:79
std::vector< std::vector< uint8_t > > state_of_dim
Definition: workspace.hpp:84
std::size_t n_states_total
number of joint states of the clique
Definition: workspace.hpp:85
Index tables for the upward (collect) message of one non-root clique u to its parent.
Definition: workspace.hpp:32
std::vector< std::vector< uint32_t > > child_maps
[child_i][prod_idx] to index in that child's up message
Definition: workspace.hpp:35
std::vector< uint32_t > pot_map
[prod_idx] to flat index in clique u's potential
Definition: workspace.hpp:34
std::size_t product_states
number of states of the product space
Definition: workspace.hpp:33
std::vector< uint32_t > marg_map
[prod_idx] to index in u's up message (its separator states)
Definition: workspace.hpp:37
std::vector< std::size_t > child_cliques
clique indices of the children, parallel to child_maps
Definition: workspace.hpp:36
Index tables for the downward (distribute) message from a parent clique p to one child clique u.
Definition: workspace.hpp:47
std::size_t product_states
number of states of the product space
Definition: workspace.hpp:48
std::vector< uint32_t > marg_map
[prod_idx] to index in u's down message
Definition: workspace.hpp:54
std::size_t parent_clique
clique index of p
Definition: workspace.hpp:55
bool has_parent_down
true when p has a parent of its own
Definition: workspace.hpp:50
std::vector< std::size_t > sibling_cliques
other children of p, parallel to sibling_maps
Definition: workspace.hpp:53
std::vector< uint32_t > down_map
[prod_idx] to index in p's down message; empty unless has_parent_down
Definition: workspace.hpp:51
std::vector< std::vector< uint32_t > > sibling_maps
[sibling_i][prod_idx] to index in that sibling's up message
Definition: workspace.hpp:52
std::vector< uint32_t > pot_map
[prod_idx] to flat index in parent clique p's potential
Definition: workspace.hpp:49