Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
a19dbfb
eval: observe-only predicted-footprint hook on CacheManager (trace le…
evaleev Jul 1, 2026
691bb42
eval: optional backend heap-stats suffix on the eval trace line
evaleev Jul 1, 2026
8e23906
eval: optional post-op memory-release hook (malloc_trim between ops)
evaleev Jul 2, 2026
bc5bd6c
eval: remove the observe-only predicted-footprint (predict) hook
evaleev Jul 3, 2026
17c00b9
tests/optimize: C60 member-2 double-proto batching probe
evaleev Jul 3, 2026
7d6abf1
optimize: plumb peak_threshold (bytes) through BatchPolicy/CostParams…
evaleev Jul 3, 2026
cd9f43f
optimize: threshold-gated batched selection (min flops s.t. peak<=P_m…
evaleev Jul 3, 2026
6223bd7
optimize: price the batch contribution buffer in reconstructed_batche…
evaleev Jul 3, 2026
24f8fdb
optimize: allow accumulation_factor for m>=2 (nested), gated by DP==o…
evaleev Jul 3, 2026
b1e42d5
optimize: reconstruct_axes emits per-node sliced-sets in RPN order
evaleev Jul 3, 2026
8d6b89d
optimize: surface per-node sliced-sets per summand via OptimizeOption…
evaleev Jul 3, 2026
53937a6
eval: EvalExpr.batch_axes_ + binarize stamps per-node sliced-sets
evaleev Jul 3, 2026
77b4c8f
eval: batched evaluator prefers the per-node annotated batch axis
evaleev Jul 4, 2026
4204ad0
eval: recursive re-entry on the batched scratch realizes nested multi…
evaleev Jul 4, 2026
8e0dcfd
eval: nested batch screening relaxation scales by the product of batc…
evaleev Jul 4, 2026
38b4721
eval: nest one batch loop per annotated axis at a multi-axis node
evaleev Jul 4, 2026
f74e5f9
optimize: floor the sliced-axis model target to >=1 to match the runtime
evaleev Jul 4, 2026
449f766
doc: design spec for size-only eval backend + PNO-CCSD size harness
evaleev Jul 4, 2026
314cfc5
doc: size-only backend sizing is a pluggable oracle (dense default), …
evaleev Jul 4, 2026
b02a9a8
doc: reframe eval-backend spec as cost-model replay (report memsize+F…
evaleev Jul 4, 2026
0c5c0aa
doc: rename eval backend brand CostToken -> DryRun (clearer for users)
evaleev Jul 4, 2026
02eae1a
dryrun: size regime + DP-inspection mechanics on pre-transform C60 re…
evaleev Jul 4, 2026
b79be90
dryrun: post-transform PAO/K verdict, CostModel, zero-data Result bac…
evaleev Jul 4, 2026
326ad9b
optimize: design perf-first (DenseTimeSpace) single-term objective
evaleev Jul 5, 2026
8d6e8ed
optimize: implementation plan for perf-first (DenseTimeSpace) objective
evaleev Jul 5, 2026
1504a96
optimize: add perf-first DenseTimeSpace{,Batched} objective
evaleev Jul 5, 2026
9a6b571
eval: dry-run C60 perf-first vs peak-first factorization comparison
evaleev Jul 5, 2026
b05fab6
eval: [dryrun-perf] report cache high watermark + diagnose the gap
evaleev Jul 5, 2026
91dd48a
eval: [dryrun-perf] optional DRYRUN_PERF_TREE schedule dump (free ixs…
evaleev Jul 5, 2026
8cda8ce
eval: [dryrun-trace] whole-residual dry-run trace to a file
evaleev Jul 5, 2026
52300a3
eval: design spec for dry-run cost-profile prediction (SQ + MPQC)
evaleev Jul 5, 2026
b678dcb
dryrun: correct a1 sizing premise and add implementation plan
evaleev Jul 5, 2026
13a2cc0
dryrun: lock power-mean sizing contract with a regression test
evaleev Jul 5, 2026
8b55749
dryrun: gated cache with batchable-axis veto and per-term reset
evaleev Jul 5, 2026
612154c
eval: opt-in scratch-fold peak sink for faithful batched-replay peak
evaleev Jul 5, 2026
1bf6f3f
dryrun: CostProfile struct and cost_profile() reusable entry point
evaleev Jul 5, 2026
db332d4
dryrun: route [dryrun-perf]/[dryrun-trace] through cost_profile
evaleev Jul 5, 2026
0102390
dryrun: correct [dryrun-perf] peak comment to the tree-proven 4-PNO W
evaleev Jul 5, 2026
4f5ca61
dryrun: RAII logger restore in cost_profile + peak/threading doc caveats
evaleev Jul 5, 2026
49d1c40
dryrun: namespace test env vars DRYRUN_* -> SEQUANT_UT_DRYRUN_*
evaleev Jul 5, 2026
059b82a
dryrun: rank-general CSV moment dispatch in SizeRegime
evaleev Jul 6, 2026
e1436f7
tests/dryrun: faithful df_regime overload + objective/moment/threshol…
evaleev Jul 6, 2026
b4d89fe
optimize: gated select_root diagnostic (chosen vs global-min frontier…
evaleev Jul 6, 2026
eca55ba
tests/dryrun: report roofline exec cost (the DP's real axis) in the d…
evaleev Jul 6, 2026
430197c
optimize: model batch recomputation cost on the flops/exec axis (opt-in)
evaleev Jul 6, 2026
816c350
optimize: enable batch recomputation charge by default
evaleev Jul 6, 2026
1aaf372
tests/dryrun: drop the superseded pre-transform investigation layer
evaleev Jul 6, 2026
533ad05
tests/dryrun: make [dryrun-perf] inspect any term/threshold + count P…
evaleev Jul 6, 2026
cf783a3
tests/dryrun: [dryrun-perf] uses the REAL measured CSV moments, not f…
evaleev Jul 6, 2026
2431923
tests/dryrun: single ProblemSize source of truth + correct pVDZ-F12 m…
evaleev Jul 6, 2026
3fc9bae
tests/dryrun: cut [dryrun-trace], hide [dryrun-df] dev sweep
evaleev Jul 6, 2026
90c339a
tests/dryrun: add [dryrun-perfcost] perf-vs-peak modelled cost sweep
evaleev Jul 7, 2026
10a0552
eval: make the core evaluate() traversal iterative (explicit stack)
evaleev Jul 7, 2026
7755751
binary_node: make deep_copy, transform_node, and the destructor itera…
evaleev Jul 7, 2026
4296286
eval dryrun: pin external-occ sizing ratio on the PPL W giant
evaleev Jul 8, 2026
954a342
optimize: recognize external occupied protoindices as batchable axes
evaleev Jul 8, 2026
a6a80ed
optimize: seed spectator external-occ into DP root frontier; size+rep…
evaleev Jul 8, 2026
aac7d3e
eval dryrun: gate P1 go/no-go within one peak model; assert DP flops …
evaleev Jul 8, 2026
1216825
optimize: emit external-occ batch axis as a forest-level signal
evaleev Jul 8, 2026
f2ae97c
optimize: domain-neutral spectator-index batching config on BatchPolicy
evaleev Jul 8, 2026
1ded293
optimize: scrub residual domain wording from ExternalBatchAxis public…
evaleev Jul 8, 2026
8d22d93
eval result: add write_into_slice block-scatter combinator (dryrun ba…
evaleev Jul 8, 2026
02be8b0
eval result: TiledArray write_into_slice; numeric-invariance vs whole…
evaleev Jul 8, 2026
d18ccb7
eval_expr: outer_proto_position accessor for proto-only spectator sli…
evaleev Jul 8, 2026
8f3eee3
eval_expr: guard outer_proto_position against mixed (plain+proto) out…
evaleev Jul 8, 2026
b50a4d2
eval: forest evaluation over a free/spectator external axis (core spine)
evaleev Jul 8, 2026
8940dee
eval: nest intra-term batching inside the external-occ forest loop
evaleev Jul 8, 2026
8a2cbfd
Merge branch 'master' into feature/eval-predicted-peak-trace
evaleev Jul 9, 2026
02f8948
eval tests: express external spectator as an aux (not occ) hyperindex
evaleev Jul 10, 2026
39c7eb7
is_valid: accept Power expressions
evaleev Jul 10, 2026
0f69597
index space registry: make occupancy predicates robust to non-physica…
evaleev Jul 10, 2026
d896b98
eval: type batch_axes_ entries with AxisKind (Contracted/External)
evaleev Jul 12, 2026
ebd95b0
optimize: admit explicit external occ modes as batchable candidates
evaleev Jul 12, 2026
5cc8ecd
optimize: reconstruct_axes emits external (spectator) modes per node
evaleev Jul 12, 2026
0f2490e
optimize: gate reconstruct_axes External emission on the perf-first p…
evaleev Jul 12, 2026
6abb853
eval: scatter (not accumulate) external batch axes into a pre-sized r…
evaleev Jul 12, 2026
18dd6b1
eval: include external batch axes in make_batched_scratch seed/sharin…
evaleev Jul 12, 2026
579b7cf
eval,optimize: retire ExternalBatchAxis forest path
evaleev Jul 12, 2026
874bfb4
eval: tests for multi-mode and Hadamard external batch axes
evaleev Jul 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions SeQuant/core/batch_policy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <cstddef>
#include <functional>
#include <limits>

namespace sequant {

Expand All @@ -21,6 +22,12 @@ struct BatchPolicy {
std::function<std::size_t(Index const&)> batch_target_size = {};
std::function<bool(Tensor const&)> is_volatile_leaf = {};

/// If true, an external/spectator index -- open on the whole network's result
/// yet contracted at no node -- is eligible for batching; its per-slice size
/// comes from \c batch_target_size(ix) like any batchable index. Default
/// false = no spectator batching (byte-identical to non-spectator behavior).
bool batch_spectator_indices = false;

/// If true, restrict batching to persistent (amplitude-independent) subtrees,
/// declining to batch any subtree that contains a volatile leaf. If false
/// (the default), batch ACROSS THE BOARD: slicing the batch axis shrinks any
Expand All @@ -40,6 +47,13 @@ struct BatchPolicy {
/// accumulator + contribution co-residency of a node that contracts a
/// batchable index.
double accumulation_factor = 0.0;

/// Peak-memory budget in BYTES for the batched objective. The single-term
/// optimizer minimizes flops among schedules whose modeled peak is <=
/// peak_threshold, falling back to min-peak (best effort) when none fit.
/// Default +infinity => every schedule feasible => min flops => no batching.
/// This is the *enable* trigger for batching (a finite value turns it on).
double peak_threshold = std::numeric_limits<double>::infinity();
};

} // namespace sequant
Expand Down
142 changes: 142 additions & 0 deletions SeQuant/core/eval/backends/dryrun/cost_model_object.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#ifndef SEQUANT_CORE_EVAL_BACKENDS_DRYRUN_COST_MODEL_OBJECT_HPP
#define SEQUANT_CORE_EVAL_BACKENDS_DRYRUN_COST_MODEL_OBJECT_HPP

#include <SeQuant/core/container.hpp>
#include <SeQuant/core/eval/backends/dryrun/size_regime.hpp>
#include <SeQuant/core/index.hpp>
#include <SeQuant/core/optimize/cost_model.hpp>
#include <SeQuant/core/optimize/options.hpp>
#include <SeQuant/core/optimize/single_term_detail.hpp>

#include <cstddef>
#include <functional>
#include <utility>

namespace sequant::eval::dryrun {

/// Per-index extent OVERRIDE table: narrows specific indices (by identity, so
/// it survives reshaping across prod/sum/permute -- the same shared/
/// contracted Index object may occupy different tensor modes at different
/// nodes) to a runtime-realized element count. Populated by
/// Result::slice_mode()/mode_batches() call sites (see result.hpp); empty =>
/// no override, the regime's nominal extent applies. This table -- not a
/// second cost model -- is what lets a zero-data DryRun Result report the
/// REALIZED (possibly runtime-sliced) size rather than always the full
/// regime extent, which is exactly the signal Task 6's replay witnesses.
using ExtentOverrides = container::map<Index, std::size_t>;

///
/// \brief Bundles the optimizer's own cost closures (memsize/flops/roofline)
/// behind one value type so dry-run Results report MODEL size (not an
/// allocated size), and the harness can additionally read FLOPs and
/// projected execution cost per operation.
///
/// This is a thin wrapper: all arithmetic is delegated verbatim to
/// \c sequant::opt::detail::memsize_counter / \c flops_counter / \c
/// roofline_op_cost (see \c core/optimize/single_term_detail.hpp and \c
/// core/optimize/cost_model.hpp) -- no parallel cost model is implemented
/// here. The only thing this class adds is the ExtentOverrides indirection:
/// each query builds a fresh (cheap; no heap allocation beyond the closure
/// itself) index-to-extent callable that consults \p overrides before
/// falling back to the SizeRegime's nominal extent, then hands that callable
/// to the counter.
///
class CostModel {
public:
explicit CostModel(SizeRegime regime, RooflineParams roofline = {})
: regime_{std::move(regime)}, roofline_{roofline} {}

///
/// \brief Bytes for a tensor with these (literal, canon-order) indices,
/// honoring any per-index extent override (a runtime slice_mode()/
/// mode_batches() narrowing).
///
/// Delegates the extent-product / composite-moment math to \c
/// memsize_counter, invoked with \p idxset as the sole (`lhs`) operand and
/// empty `rhs`/`result` -- an empty operand's tot_indices() split
/// accumulates the starting product of 1.0, which memsize_counter itself
/// special-cases to contribute zero bytes, so this reproduces exactly the
/// single-operand byte count \c memsize_counter is designed to report per
/// operand.
///
[[nodiscard]] std::size_t memsize(
container::svector<Index> const& idxset,
ExtentOverrides const& overrides = {}) const {
auto const ext = make_extent_fn(overrides);
auto const mc =
sequant::opt::detail::memsize_counter(ext, regime_.inner_pow_fn());
double const elems =
mc(idxset, container::svector<Index>{}, container::svector<Index>{});
return static_cast<std::size_t>(elems * numeric_size_);
}

///
/// \brief Multiply-add count for a contraction whose free (result) indices
/// are \p out and whose contracted (summed-over) indices are
/// \p contracted.
///
/// Delegates to \c flops_counter, which prices the union of its (lhs, rhs,
/// result) arguments; passing (\p out, \p contracted, {}) makes that union
/// exactly `out U contracted` -- the full index set touched by the
/// contraction, since by construction `contracted` holds precisely the
/// indices present in both operands but absent from the result.
///
[[nodiscard]] double flops(container::svector<Index> const& out,
container::svector<Index> const& contracted,
ExtentOverrides const& overrides = {}) const {
auto const ext = make_extent_fn(overrides);
auto const fc =
sequant::opt::detail::flops_counter(ext, regime_.inner_pow_fn());
return fc(out, contracted, container::svector<Index>{});
}

///
/// \brief Roofline-projected execution cost of one contraction (see
/// \c sequant::opt::detail::roofline_op_cost).
///
/// \p left_bytes / \p right_bytes are operand footprints in BYTES (as
/// reported by \c Result::size_in_bytes()); converted to elements (the
/// counter's native unit) via \c numeric_size before delegating.
///
[[nodiscard]] double exec_cost(double flops_count, std::size_t left_bytes,
std::size_t right_bytes) const {
double const traffic_elems =
static_cast<double>(left_bytes + right_bytes) / numeric_size_;
return sequant::opt::detail::roofline_op_cost(
flops_count, traffic_elems, roofline_.machine_balance,
roofline_.fast_mem_elems, roofline_.block_tiles,
roofline_.block_prefactor);
}

[[nodiscard]] SizeRegime const& regime() const noexcept { return regime_; }

private:
// Index-to-extent callable consulting `overrides` first, else the
// regime's nominal extent. The returned std::function captures `overrides`
// (and `this`) BY REFERENCE and is only ever used -- never stored --
// within the (memsize/flops) call that constructs it, so the reference
// stays valid for its entire lifetime. Explicit (non-deduced) return type
// so this can be called from memsize()/flops(), which appear earlier in
// the class body (a deduced `auto` return type would require the
// definition to precede every use, even within the same class).
[[nodiscard]] std::function<std::size_t(Index const&)> make_extent_fn(
ExtentOverrides const& overrides) const {
return [this, &overrides](Index const& ix) -> std::size_t {
if (auto it = overrides.find(ix); it != overrides.end())
return it->second;
return regime_.extent(ix);
};
}

SizeRegime regime_;
RooflineParams roofline_;
// sizeof(double); see doc/dev/plans/2026-07-04-dryrun-eval-backend.md Task 2
// note on OptimizeOptions::numeric_size (hardcoded here, matching the C60
// trace's real-only CSV-CCk path; complex CSV-CCk is out of scope, see the
// plan's carried-minor N4).
double numeric_size_ = 8.0;
};

} // namespace sequant::eval::dryrun

#endif // SEQUANT_CORE_EVAL_BACKENDS_DRYRUN_COST_MODEL_OBJECT_HPP
Loading
Loading