use super::*;
pub fn verify_pick_all_with_pipeline(
model: &dyn Model,
argmax_ids: &[u32],
a: &mut ActiveSeq,
ctx: &LogitsContext,
row_base: usize,
) -> Vec<u32> {
use crate::scheduler::mtp_timing::Phase;
let k = argmax_ids.len();
if k == 0 {
return Vec::new();
}
if let Some(picks) = fast_masked::try_chat_fast_path(model, argmax_ids, a, ctx, row_base) {
return picks;
}
let eos_held = crate::scheduler::eos_hold::eos_masked_in_window(a, argmax_ids);
let fast_penalty_gate = if ctx.sampling.fast_greedy_grammar
&& a.grammar_state.is_some()
&& !a.inside_thinking
&& !eos_held
&& (a.temperature == 0.0 || ctx.sampling.force_temp_zero)
{
crate::scheduler::fast_greedy::classify_penalties(
&crate::scheduler::sample_step::penalty_params_for(
a,
crate::scheduler::sample_step::PositionKind::Verify,
0.0,
None,
Vec::new(),
ctx.watchdog.min_reasoning_floor,
),
)
} else {
crate::scheduler::fast_greedy::PenaltyGate::Blocked
};
if fast_penalty_gate != crate::scheduler::fast_greedy::PenaltyGate::Blocked {
let t_fast = ctx.clock.now();
let vocab = model.vocab_size();
let logits_base = model.logits_buffer_ptr();
let scoped_history: Vec<u32> =
if fast_penalty_gate == crate::scheduler::fast_greedy::PenaltyGate::ReduceOnly {
crate::scheduler::sample_step::penalty_history_scope(
&a.output_tokens,
ctx.tool_call_end_token,
)
.to_vec()
} else {
Vec::new()
};
let before = a.grammar_state.as_ref().map(|gs| gs.num_history_steps());
let mut fast: Vec<u32> = Vec::with_capacity(k);
let mut all_allowed = true;
{
let Some(gs) = a.grammar_state.as_mut() else {
unreachable!("grammar_state present (gated by is_some above)")
};
for (i, &tok) in argmax_ids.iter().enumerate() {
if fast_penalty_gate == crate::scheduler::fast_greedy::PenaltyGate::ReduceOnly
&& !crate::scheduler::fast_greedy::argmax_immune(tok, &scoped_history, || {
crate::scheduler::fast_greedy::logit_is_positive(
model,
logits_base,
row_base + i,
vocab,
tok,
)
})
{
all_allowed = false;
break;
}
let allowed = if gs.is_terminated() {
true
} else {
gs.fill_bitmask();
gs.is_token_allowed(tok)
};
if !allowed {
all_allowed = false;
break;
}
fast.push(tok);
if i + 1 < k && !gs.is_terminated() {
let _ = gs.accept_token(tok);
}
}
}
if let (Some(b), Some(gs)) = (before, a.grammar_state.as_mut()) {
let adv = gs.num_history_steps().saturating_sub(b);
if adv > 0 {
gs.rollback(adv);
}
}
ctx.tel.mark(Phase::FastGreedy, t_fast);
if all_allowed && fast.len() == k {
return fast;
}
}
let chat_fast_gate = if ctx.sampling.fast_greedy_chat
&& a.grammar_state.is_none()
&& !a.inside_thinking
&& !eos_held
&& (a.temperature == 0.0 || ctx.sampling.force_temp_zero)
{
crate::scheduler::fast_greedy::classify_penalties(
&crate::scheduler::sample_step::penalty_params_for(
a,
crate::scheduler::sample_step::PositionKind::Verify,
0.0,
None,
Vec::new(),
ctx.watchdog.min_reasoning_floor,
),
)
} else {
crate::scheduler::fast_greedy::PenaltyGate::Blocked
};
if chat_fast_gate != crate::scheduler::fast_greedy::PenaltyGate::Blocked {
let t_fast = ctx.clock.now();
let vocab = model.vocab_size();
let logits_base = model.logits_buffer_ptr();
let scoped_history: Vec<u32> =
if chat_fast_gate == crate::scheduler::fast_greedy::PenaltyGate::ReduceOnly {
crate::scheduler::sample_step::penalty_history_scope(
&a.output_tokens,
ctx.tool_call_end_token,
)
.to_vec()
} else {
Vec::new()
};
let all_immune = argmax_ids.iter().enumerate().all(|(i, &tok)| {
chat_fast_gate == crate::scheduler::fast_greedy::PenaltyGate::Neutral
|| crate::scheduler::fast_greedy::argmax_immune(tok, &scoped_history, || {
crate::scheduler::fast_greedy::logit_is_positive(
model,
logits_base,
row_base + i,
vocab,
tok,
)
})
});
ctx.tel.mark(Phase::FastGreedy, t_fast);
if all_immune {
return argmax_ids.to_vec();
}
}
let vocab = model.vocab_size();
let elem_bytes = 2usize;
let total = k * vocab * elem_bytes;
let t_d2h = ctx.clock.now();
let mut buf = vec![0u8; total];
if model
.copy_logits_to_host(
model
.logits_buffer_ptr()
.offset(row_base * vocab * elem_bytes),
&mut buf,
)
.is_err()
{
return argmax_ids.to_vec();
}
ctx.tel.mark(Phase::D2h, t_d2h);
pick_positions::pick_positions_from_host(&buf, vocab, elem_bytes, k, a, ctx)
}