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

Qiskit / qiskit / 26904388576

03 Jun 2026 06:20PM UTC coverage: 87.482% (-0.05%) from 87.529%
26904388576

Pull #16298

github

web-flow
Merge 89f511c86 into 560b91c67
Pull Request #16298: Refactor ProgramNode::call to flatten+call_flat+unflatten

220 of 250 new or added lines in 3 files covered. (88.0%)

576 existing lines in 13 files now uncovered.

108927 of 124513 relevant lines covered (87.48%)

962192.97 hits per line

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

10.71
/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};
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 {
NEW
35
    fn from(e: TreeMatchError) -> Self {
×
NEW
36
        match e {
×
NEW
37
            TreeMatchError::MissingPath { path } => Self::MissingInput { key: path },
×
NEW
38
            TreeMatchError::ExpectedLeaf { path } => Self::ExpectedLeaf { key: path },
×
39
        }
NEW
40
    }
×
41
}
42

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

48
impl MissingCallError {
49
    /// Construct a new [`MissingCallError`] tagged with the node's full name.
NEW
50
    pub fn new(name: impl Into<String>) -> Self {
×
NEW
51
        Self(name.into())
×
NEW
52
    }
×
53
}
54

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

70
impl<E> From<ArityMismatch> for CallError<E> {
NEW
71
    fn from(e: ArityMismatch) -> Self {
×
NEW
72
        Self::OutputArityMismatch {
×
NEW
73
            expected: e.expected,
×
NEW
74
            actual: e.actual,
×
NEW
75
        }
×
NEW
76
    }
×
77
}
78

79
/// A node in a quantum program graph that transforms tensors.
80
pub trait ProgramNode {
81
    type CallError;
82

83
    /// The name of this program node.
84
    fn name(&self) -> &str;
85

86
    /// The namespace this program node belongs to.
87
    fn namespace(&self) -> &str;
88

89
    /// The namespace and name as one string.
90
    fn full_name(&self) -> String {
1✔
91
        format!("{}.{}", self.namespace(), self.name())
1✔
92
    }
1✔
93

94
    /// The inputs expected at call time.
95
    fn input_types(&self) -> &DataTree<TensorType>;
96

97
    /// The outputs promised on call return.
98
    fn output_types(&self) -> &DataTree<TensorType>;
99

100
    /// Whether this program node implements the call method.
101
    fn implements_call(&self) -> bool;
102

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

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

138
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