# Comment evaluation corpus -- rust-pybamm, needs labels
#
# Real own-line comments with the code that follows. Mark every `verdict:` as:
#
#   slop  - should not exist: restates the code, narrates an edit, labels a
#           section, leaks process, records history, or is a long explanation
#           where a short one would do
#   keep  - deleting it would lose a fact not recoverable from the code
#   skip  - genuinely cannot tell without more context
#
# Leave `?` on anything you do not reach; partial labelling still scores.
#
# Nothing here reveals which rule (if any) fires on a case, or how the case
# was sampled.

### 1  pybamm-core/src/adjoint.rs:422
# A block never contains a `Dispatch`, so replaying one needs no
# further span handling.
    for k in (start..start + len as usize).rev() {
    backward_instruction(consts, instructions[k], scratch, bar, grad);
    }
    walked += len as usize;
verdict: keep

### 2  pybamm-core/src/const_entries.rs:911
# A reduction over the whole state is not modelled element-wise, so its
# row is swept even though the summed rows are linear.
    let mut arena = Arena::new();
    let y = arena.alloc(Node::StateVector { start: 0, end: 3 });
    let reduced = arena.alloc(Node::MaxReduce(y));
    let root = arena.alloc(Node::Concat(vec![reduced, y]));
verdict: keep

### 3  pybamm-core/src/eval_batch.rs:419
# Slot elements [start, start+len) map to contiguous lane blocks,
# so the whole window is one contiguous copy (memmove-safe).
    let s = (src as usize + start as usize) * k;
    let n = len as usize * k;
    buf.copy_within(s..s + n, dst as usize * k);
    },
verdict: ?

### 4  pybamm-core/src/ir.rs:1026
# A `Conditional`'s branch slots are the one legitimate
# outside read of a block-owned value.
    if src.is_branch_slot {
    continue;
    }
    let start = src.offset as usize;
verdict: ?

### 5  pybamm-core/src/model.rs:1529
# A tail block may carry fewer colours than its stride; the surplus
# lanes are never seeded, so they stay zero and scatter nothing.
    let carried = stride.min(n_colors - block);
    self.write_seed_lanes(ws, block, carried, stride, 1.0);
    let result = self.run_tangent_lanes(ws, stride);
    for lane in 0..carried {
verdict: keep

### 6  pybamm-core/src/model.rs:3869
# Build a model where some Jacobian columns are structurally zero
# Verify that zero propagation eliminates dead computation
    let mut arena = Arena::new();
    let y_full = arena.alloc(Node::StateVector { start: 0, end: 2 });
    let y0 = arena.alloc(Node::Index {
verdict: keep

### 7  pybamm-core/src/model.rs:3873
# f(y) = [y0 * y1, y0 + c], so df/dy = [[y1, y0], [1, 0]] and
# df1/dy1 is a structural zero.
    let y_full = arena.alloc(Node::StateVector { start: 0, end: 2 });
    let y0 = arena.alloc(Node::Index {
    child: y_full,
    start: 0,
verdict: keep

### 8  pybamm-core/src/model.rs:4147
# Loop B (COO), cj = 0 -> J = df/dy.
    model.set_cj(0.0);
    let (rows, cols, vals) = model.assemble_jacobian(0.0, &y, &[]);
    assert_matrices_match(
    &coo_to_dense(&rows, &cols, &vals, n),
verdict: ?

### 9  pybamm-core/src/model.rs:4558
# Build tridiagonal-like structure
# f(y) = [y0+y1, y0+y1+y2, y1+y2]
    let mut arena = Arena::new();
    let y0 = arena.alloc(Node::StateVector { start: 0, end: 1 });
    let y1 = arena.alloc(Node::StateVector { start: 1, end: 2 });
    let y2 = arena.alloc(Node::StateVector { start: 2, end: 3 });
verdict: keep

### 10  pybamm-core/src/model.rs:4956
# y = [3.0, 4.0] => output = 6.0, event = 2.5
    let mut out_val = [0.0; 1];
    let mut event_val = [0.0; 1];
    model.eval_output(0.0, &[3.0, 4.0], &[], 0, &mut out_val);
    model.eval_event(0.0, &[3.0, 4.0], &[], 0, &mut event_val);
verdict: keep

### 11  pybamm-core/src/model.rs:5289
# RHS: k * y (2-vector)
    let rhs = arena.alloc(Node::Mul(k, y_full));
    let y0_sq = arena.alloc(Node::Pow(y0, two));
    let ky0_sq = arena.alloc(Node::Mul(k, y0_sq));
    let event_node = arena.alloc(Node::Sub(ky0_sq, one));
verdict: keep

### 12  pybamm-core/src/simplify.rs:572
# x - 0 -> x, exact only from +0.0 (x = -0.0 would flip positive).
# Aggressive already normalises zero's sign, as `0 - x` below does.
    if is_positive_zero(arena, rhs_s) || (mode == SimplifyMode::Aggressive && is_zero(arena, rhs_s))
    {
    return lhs_s;
    }
verdict: keep

### 13  pybamm-core/src/simplify.rs:715
# powf is ~30x an elementwise multiply, and a multiply/divide chain keeps
# the IEEE special cases (sign of zero, infinities, NaN) exact.
    if let Some(e) = get_scalar(arena, exp_s)
    && let Some(id) = lower_int_pow(arena, base_s, e)
    {
    return id;
verdict: keep

### 14  pybamm-core/src/simplify.rs:1008
# The sign is explicitly NOT guaranteed; assert only that we know which
# way it went, so a future change to the contract fails loudly here.
    assert!(a.is_sign_positive(), "unfolded -0.0 + 0.0 is +0.0");
    assert!(b.is_sign_negative(), "folded form keeps -0.0");
    }
    fn test_fold_sub_zero() {
verdict: keep

### 15  pybamm-core/src/solver/mod.rs:560
# df/dy = diag(-1, -2). Collect the assembled triplets and check.
    let mut diag = [0.0f64; 2];
    let (indices, values) = jac.triplet_iter();
    for ((row, col), val) in indices.zip(values) {
    assert_eq!(row, col, "jacobian must be diagonal, got ({row},{col})");
verdict: ?

### 16  pybamm-core/src/solver/mod.rs:598
# beta == 3: y = M @ x + beta * y_old = x + 3*y_old
# = [1 + 30, 2 + 60] = [31, 62]
    mass.gemv_inplace(&x, 0.0, 3.0, &mut y);
    assert!(
    (y.as_slice()[0] - 31.0).abs() < 1e-12,
    "y0={}",
verdict: ?

### 17  pybamm-core/src/solver/mod.rs:766
# dy/dt = -y, y(0) = 1, output = 2*y, event = y - 0.5 (root at t = ln 2).
# Output and state differ there, so y_event tells them apart.
    let mut arena = Arena::new();
    let sv = arena.alloc(Node::StateVector { start: 0, end: 1 });
    let neg = arena.alloc(Node::Scalar(-1.0));
    let rhs_expr = arena.alloc(Node::Mul(neg, sv));
verdict: ?

### 18  pybamm-core/src/solver/mod.rs:874
# Differential: y0' = -y0.  Algebraic: 0 = 2*y0 - y1  (=> y1 = 2*y0).
# Mass = diag(1, 0).
    let mut arena = Arena::new();
    let sv0 = arena.alloc(Node::StateVector { start: 0, end: 1 });
    let sv1 = arena.alloc(Node::StateVector { start: 1, end: 2 });
    let neg1 = arena.alloc(Node::Scalar(-1.0));
verdict: keep

### 19  pybamm-core/src/solver/solve.rs:2099
# Nothing to differentiate is a caller mistake, not a zero-column solve: the
# wrapper has no columns to present and the augmented state has no shape.
    let prepared = build_decay_without_sens_params();
    let err = prepared
    .solve(
    SolveRequest::new(&[0.0, 0.1]).with_sensitivities(),
verdict: keep

### 20  pybamm-core/src/solver/solve.rs:2603
# The root column is read off the state after state_mut_back, so its
# yp must be the root-time slope, not the overshot step's.
    let prepared = build_decay_param_output_event().with_store_yp(true);
    let t_eval: Vec<f64> = (0..=20).map(|i| f64::from(i) * 0.1).collect();
    let r = prepared
    .solve(SolveRequest::new(&t_eval), InputSet::new(&[1.0], &[1.0]))
verdict: ?

### 21  pybamm-core/src/sparsity.rs:366
# Argmax/argmin is runtime-dependent, so the static pattern must
# union deps over the whole reduced vector (deps(basis) subset of deps(picker)).
    let mut combined = child_deps(deps, *basis).union_all(n_states);
    combined.union_with(&child_deps(deps, *picker).union_all(n_states));
    ElementDeps::Scalar(combined)
    },
verdict: keep

### 22  pybamm-core/src/sparsity.rs:640
# Output depends on states 0 and 1
    assert_eq!(pattern.nrows, 2);
    assert_eq!(pattern.ncols, 4);
    assert_eq!(
    &pattern.indices[pattern.indptr[0]..pattern.indptr[1]],
verdict: ?

### 23  pybamm-core/src/sparsity.rs:1074
# over Arena::topological_order makes this trivially bounded by
# heap, not stack.
    let mut arena = Arena::new();
    let y = arena.alloc(Node::StateVector { start: 0, end: 1 });
    let mut current = y;
    for _ in 0..5000 {
verdict: keep

### 24  pybamm-core/src/tangent.rs:149
# Constants - derivative is 0
    Node::Scalar(_)
    | Node::Array(_)
    | Node::ZeroVector { .. }
    | Node::SparseMatrix(_)
verdict: keep

### 25  pybamm-core/src/tangent.rs:510
# Picks the tangent component at the argmax, ties going to the first
# occurrence, as `ReduceArgSelect` evaluation does for the primal.
    Node::MaxReduce(a) => {
    let da = differentiate(arena, a, mode, memo, state_filter, widths);
    arena.alloc(Node::ReduceArgSelect {
    basis: da,
verdict: keep

### 26  pybamm-core/src/tangent.rs:710
# f = concat(empty_vec[], y0 + 1); mirrors a pure-algebraic PyBaMM model
# (concatenated_rhs is a length-0 Vector). df/dy0 must land at row 0,
# not be swallowed by a phantom length-1 zero for the length-0 child.
    use crate::node::ArrayData;
    let mut arena = Arena::new();
    let empty = arena.alloc(Node::Array(Box::new(ArrayData {
    data: vec![],
verdict: slop

### 27  pybamm-core/src/tangent.rs:1311
# d(concat(x, y)) = concat(dx, dy)
    let mut arena = Arena::new();
    let x = arena.alloc(Node::StateVector { start: 0, end: 2 });
    let y = arena.alloc(Node::StateVector { start: 2, end: 4 });
    let concat = arena.alloc(Node::Concat(vec![x, y]));
verdict: ?

### 28  pybamm-core/src/tangent.rs:1718
# x * x reaches the same child twice, so the memo is what keeps one
# tangent of x rather than two.
    let mut arena = Arena::new();
    let x = arena.alloc(Node::StateVector { start: 0, end: 1 });
    let x_sq = arena.alloc(Node::Mul(x, x));
    let jac = tangent_wrt_states(&mut arena, x_sq);
verdict: ?

### 29  pybamm-core/src/tangent.rs:1980
# f = x0^2 + 3*x1, differentiate only w.r.t. x1
# df/dx1 = 3 (x0 treated as constant)
    let mut arena = Arena::new();
    let x0 = arena.alloc(Node::StateVector { start: 0, end: 1 });
    let x1 = arena.alloc(Node::StateVector { start: 1, end: 2 });
    let x0_sq = arena.alloc(Node::Mul(x0, x0));
verdict: ?

### 30  pybamm-core/tests/proptest_ad.rs:57
# Central finite difference: (f(y + h*seed) - f(y - h*seed)) / (2h)
    let y_plus: Vec<f64> = case
    .y
    .iter()
    .zip(seed.iter())
verdict: ?

### 31  pybamm-core/tests/test_branch_shortcircuit.rs:67
# Growing branch 3 must not change what branch 1 costs. This is the
# invariant `test_unified_active_branch_independent_of_other_modes` checks.
    let cost_of_branch_one = |depth_of_last: usize| {
    let mut arena = Arena::new();
    let y = arena.alloc(Node::StateVector { start: 0, end: 1 });
    let sel = arena.alloc(Node::InputParameter {
verdict: ?

### 32  pybamm-core/tests/test_branch_shortcircuit.rs:878
# y + two selectors + two Conditionals + Add + two Dispatches.
    let common = 8;
    let y0 = 0.3_f64;
    let d_chain = |depth: usize, tanh: bool| {
    let mut derivative = 1.0_f64;
verdict: ?

### 33  pybamm-core/tests/test_coloring_correctness.rs:247
# With cj != 0 the assembled Jacobian is df/dy - cj*M, while FD gives df/dy,
# so cj*M is subtracted here.
    let n = 10;
    let mut model = build_banded_model(n);
    let cj = 0.5;
    model.set_cj(cj);
verdict: ?

### 34  pybamm-core/tests/test_sparsity_oracle.rs:15
# Frozen copy of `sparsity.rs::analyze_output_dependencies` and its helpers,
# renamed with an `Oracle` suffix, kept as an independent implementation.
    enum ElementDepsOracle {
    Scalar(HashSet<usize>),
    Vector(Vec<HashSet<usize>>),
    }
verdict: slop

### 35  pybamm-core/tests/test_split_eval.rs:175
# Verify calling eval_tangent many times after a single eval_primal
# produces correct results every time (no buffer corruption).
    let mut arena = Arena::new();
    let y = arena.alloc(Node::StateVector { start: 0, end: 5 });
    let exp_y = arena.alloc(Node::Exp(y));
    let two = arena.alloc(Node::Scalar(2.0));
verdict: keep

### 36  pybamm-python/src/evaluator_pool.rs:32
# out one address per index, and `create_rust_solver_group` gives each address
# to exactly one `IDAKLUSolver`. Distinct solvers therefore mutate distinct
# evaluators, and the `CompiledModel` they share behind the `Arc` is immutable.
    unsafe impl Sync for EvaluatorPool {}
    impl std::fmt::Debug for EvaluatorPool {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.debug_struct("EvaluatorPool")
verdict: slop

### 37  pybamm-python/src/model.rs:135
# scipy CSR arrays arrive as i64; convert with a bounds check so a
# negative entry becomes a clear error rather than a wrapped `usize`.
    let indptr: Vec<usize> = mass_indptr
    .iter()
    .map(|&x| usize::try_from(x))
    .collect::<Result<_, _>>()
verdict: ?

### 38  pybamm-python/src/model.rs:151
# `new_wrt_state_subset` asserts a strictly-ascending subset; callers pass
# a contiguous range, but normalise so the invariant holds regardless.
    let mut algebraic_variable_indices = algebraic_variable_indices;
    algebraic_variable_indices.sort_unstable();
    algebraic_variable_indices.dedup();
    let g = graph.try_borrow(py).map_err(|_| {
verdict: keep

### 39  pybamm-python/src/model.rs:280
# Expr -> NodeId conversions: the bundle retains the roots so the view
# accessors can compose prepared artifacts over the shared tapes.
    let rhs_root = expr.node_id_in(&graph)?;
    let output_roots: Vec<NodeId> = output_exprs
    .iter()
    .map(|e| e.node_id_in(&graph))
verdict: ?

### 40  pybamm-python/src/pool.rs:73
# Integer keys run no arbitrary Python, so set_item cannot re-enter
# pool_for and the cache stays locked for the whole build.
    for (threads, pool) in lock_cache().iter() {
    dict.set_item(threads, Arc::as_ptr(pool) as usize)?;
    }
    Ok(dict.unbind())
verdict: keep
