• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Qiskit / qiskit / 26571408919

28 May 2026 11:17AM UTC coverage: 87.601% (-0.06%) from 87.662%
26571408919

Pull #16299

github

web-flow
Merge 5a513c87a into e68d23c4c
Pull Request #16299: Add ShotLoop impl of QuantumProgram

1618 of 1902 new or added lines in 9 files covered. (85.07%)

34 existing lines in 5 files now uncovered.

109808 of 125350 relevant lines covered (87.6%)

949088.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.0
/crates/providers/src/program_node.rs
1
// This code is part of Qiskit.
2
//
3
// (C) Copyright IBM 2026
4
//
5
// This code is licensed under the Apache License, Version 2.0. You may
6
// obtain a copy of this license in the LICENSE.txt file in the root directory
7
// of this source tree or at https://www.apache.org/licenses/LICENSE-2.0.
8
//
9
// Any modifications or derivative works of this code must retain this
10
// copyright notice, and modified files need to carry a notice indicating
11
// that they have been altered from the originals.
12

13
use crate::data_tree::{ArityMismatch, DataTree, TreeMatchError, format_path};
14
use crate::tensor::{DType, Tensor, TensorType};
15
use thiserror::Error;
16

17
/// Errors returned when a tree-shaped argument does not match [`ProgramNode::input_types`].
18
#[derive(Debug, Clone, PartialEq, Eq, Error)]
19
pub enum CallInputError {
20
    #[error("missing required input {key:?}")]
21
    MissingInput { key: String },
22

23
    #[error("expected a leaf at {key:?}, found a branch")]
24
    ExpectedLeaf { key: String },
25

26
    #[error("unexpected dtype at {key:?}: expected {expected}, found {actual}")]
27
    UnexpectedDType {
28
        key: String,
29
        expected: String,
30
        actual: DType,
31
    },
32
}
33

34
impl From<TreeMatchError> for CallInputError {
35
    fn from(e: TreeMatchError) -> Self {
4✔
36
        match e {
4✔
37
            TreeMatchError::MissingPath { path } => Self::MissingInput {
1✔
38
                key: format_path(&path).to_string(),
1✔
39
            },
1✔
40
            TreeMatchError::ExpectedLeaf { path } => Self::ExpectedLeaf {
3✔
41
                key: format_path(&path).to_string(),
3✔
42
            },
3✔
43
        }
44
    }
4✔
45
}
46

47
/// Returned by implementations with a missing call implementation when called.
48
#[derive(Debug, Clone, PartialEq, Eq, Error)]
49
#[error("node {0:?} does not implement call()")]
50
pub struct MissingCallError(pub String);
51

52
impl MissingCallError {
53
    /// Construct a new [`MissingCallError`] tagged with the node's full name.
54
    pub fn new(name: impl Into<String>) -> Self {
2✔
55
        Self(name.into())
2✔
56
    }
2✔
57
}
58

59
/// Errors returned by [`ProgramNodeExt::call`].
60
#[derive(Debug, Error)]
61
pub enum CallError<E> {
62
    /// The input tree did not match the contract declared by `input_types()`.
63
    #[error(transparent)]
64
    Input(CallInputError),
65
    /// The node's [`ProgramNode::call_flat`] returned an error.
66
    #[error(transparent)]
67
    Call(E),
68
    /// The node's [`ProgramNode::call_flat`] returned a vector whose length
69
    /// did not match the leaf count of `output_types()`.
70
    #[error("call_flat returned {actual} outputs, expected {expected}")]
71
    OutputArityMismatch { expected: usize, actual: usize },
72
}
73

74
impl<E> From<ArityMismatch> for CallError<E> {
NEW
75
    fn from(e: ArityMismatch) -> Self {
×
NEW
76
        Self::OutputArityMismatch {
×
NEW
77
            expected: e.expected,
×
NEW
78
            actual: e.actual,
×
NEW
79
        }
×
NEW
80
    }
×
81
}
82

83
/// A node in a quantum program graph that transforms tensors.
84
pub trait ProgramNode {
85
    type CallError;
86

87
    /// The name of this program node.
88
    fn name(&self) -> &str;
89

90
    /// The namespace this program node belongs to.
91
    fn namespace(&self) -> &str;
92

93
    /// The namespace and name as one string.
94
    fn full_name(&self) -> String {
4✔
95
        format!("{}.{}", self.namespace(), self.name())
4✔
96
    }
4✔
97

98
    /// The inputs expected at call time.
99
    fn input_types(&self) -> &DataTree<TensorType>;
100

101
    /// The outputs promised on call return.
102
    fn output_types(&self) -> &DataTree<TensorType>;
103

104
    /// Whether this program node implements the call method.
105
    fn implements_call(&self) -> bool;
106

107
    /// The action of this program node with flattened I/O.
108
    ///
109
    /// `args` is in input-tree DFS leaf order matching `input_types()` and
110
    /// the returned vector is in output-tree DFS leaf order matching
111
    /// `output_types()`.
112
    ///
113
    /// # Panics
114
    ///
115
    /// Implementations are allowed to panic if `args.len()` does not equal
116
    /// the leaf count of `input_types()`; callers are responsible for upholding
117
    /// this invariant. On the other hand, implementations should raise a call
118
    /// error if they find tensors that they don't like.
119
    /// [`ProgramNodeExt::call`] and [`QuantumProgram::call_flat`] both do.
120
    fn call_flat(&self, args: &[Tensor]) -> Result<Vec<Tensor>, Self::CallError>;
121
}
122

123
/// Extension with the wrapper over [`ProgramNode::call_flat`] whose I/O are data trees.
124
///
125
/// Provided via a blanket impl over every `T: ProgramNode` so that it cannot
126
/// be overridden in stable Rust.
127
pub trait ProgramNodeExt: ProgramNode {
128
    /// The action of this program node.
129
    fn call(
4✔
130
        &self,
4✔
131
        args: &DataTree<Tensor>,
4✔
132
    ) -> Result<DataTree<Tensor>, CallError<Self::CallError>> {
4✔
133
        let flat = self
4✔
134
            .input_types()
4✔
135
            .flatten_against(args)
4✔
136
            .map_err(|e| CallError::Input(e.into()))?;
4✔
NEW
137
        let out = self.call_flat(&flat).map_err(CallError::Call)?;
×
NEW
138
        self.output_types().unflatten(out).map_err(Into::into)
×
139
    }
4✔
140
}
141

142
impl<T: ProgramNode + ?Sized> ProgramNodeExt for T {}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc