1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
use super::*;
use crate::instruction::InstructionId;
use crate::wire::Wire;
use std::collections::HashMap;
/// DAG Methods
impl QuditCircuit {
/// Distill the circuit front nodes into a hashmap.
///
/// # Returns
///
/// A mapping from qudit or dit index to a circuit point of the first
/// operation in the circuit on that qudit or clbit.
///
/// # Performance
///
/// This method is O(|width|) where width includes both the number of
/// qudits and number of classical dits in the circuit.
///
/// # Notes
///
/// The same instruction id may be pointed to
/// by two different keys in the hash map if it is at the front of
/// the circuit at multiple spots. For example, if a cnot was at the
/// front of the circuit, then it would be pointed to by both the
/// control and target qudit indices.
///
/// # Examples
///
/// ```
/// # use qudit_circuit::QuditCircuit;
/// # use qudit_circuit::Wire;
/// # use qudit_expr::library::{PGate, HGate};
/// let mut circuit = QuditCircuit::pure([2, 2]);
/// let p_id = circuit.append(PGate(2), 0, None).unwrap();
/// let h_id = circuit.append(HGate(2), 1, None).unwrap();
/// assert_eq!(circuit.front().len(), 2);
/// assert_eq!(circuit.front()[&Wire::quantum(0)], p_id);
/// assert_eq!(circuit.front()[&Wire::quantum(1)], h_id);
/// ```
pub fn front(&self) -> HashMap<Wire, InstructionId> {
self.front
.iter()
.map(|(wire, front_cycle_id)| {
let front_cycle = self
.cycles
.get_from_id(*front_cycle_id)
.expect("Expected cycle to exist.");
let front_inst_id = front_cycle
.get_id_from_wire(*wire)
.expect("Expected there to be an instruction here?");
(*wire, InstructionId::new(*front_cycle_id, front_inst_id))
})
.collect()
}
/// Distill the circuit rear nodes into a hashmap.
///
/// See [`QuditCircuit::front`] for more information.
pub fn rear(&self) -> HashMap<Wire, InstructionId> {
self.rear
.iter()
.map(|(wire, rear_cycle_id)| {
let rear_cycle = self
.cycles
.get_from_id(*rear_cycle_id)
.expect("Expected cycle to exist.");
let rear_inst_id = rear_cycle
.get_id_from_wire(*wire)
.expect("Expected there to be an instruction here?");
(*wire, InstructionId::new(*rear_cycle_id, rear_inst_id))
})
.collect()
}
/// Get the first instruction on a wire.
///
/// # Returns
///
/// An instruction id pointing to the first instruction on the specified wire
/// if it exists. None, otherwise.
///
/// # Performance
///
/// This method is O(1)
///
/// # Examples
///
/// ```
/// # use qudit_circuit::QuditCircuit;
/// # use qudit_circuit::Wire;
/// # use qudit_expr::library::PGate;
/// let mut circuit = QuditCircuit::pure([2]);
/// let p_id = circuit.append(PGate(2), 0, None).unwrap();
/// assert_eq!(circuit.first_on(Wire::quantum(0)), Some(p_id));
/// ```
pub fn first_on<W: Into<Wire>>(&self, wire: W) -> Option<InstructionId> {
let wire = wire.into();
self.front.get(&wire).map(|cycle_id| {
InstructionId::new(
*cycle_id,
self.cycles[*cycle_id]
.get_id_from_wire(wire)
.expect("Expected instruction to exist."),
)
})
}
/// Get the last instruction on a wire.
///
/// See [`QuditCircuit::first_on`] for more information.
pub fn last_on<W: Into<Wire>>(&self, wire: W) -> Option<InstructionId> {
let wire = wire.into();
self.rear.get(&wire).map(|cycle_id| {
InstructionId::new(
*cycle_id,
self.cycles[*cycle_id]
.get_id_from_wire(wire)
.expect("Expected instruction to exist."),
)
})
}
/// Gather the points of the next operations from the point of an operation.
///
/// # Arguments
///
/// * `point` - The point to get the next operations from. This needs refer
/// to a valid point in the circuit.
///
/// # Returns
///
/// A mapping from qudit or clbit index to the point of the next operation
/// on that qudit or clbit.
///
/// # Performance
///
/// This method is O(|op-width|) where op-width includes both the number of
/// qudits and number of classical dits in the operation referred to by
/// `point`.
///
/// # Panics
///
/// If `point` is not a valid point in the circuit.
///
/// # Notes
///
/// The same operation may be pointed to by two different keys in the hash
/// map if it is the next of the operation at multiple spots. For
/// example, if a cnot is after the pointed operation, then it would be
/// pointed to by both the control and target qudit indices in the returned
/// map.
///
/// # Examples
///
/// ```
/// # use qudit_circuit::QuditCircuit;
/// # use qudit_circuit::Wire;
/// # use qudit_expr::library::{PGate, HGate};
/// let mut circuit = QuditCircuit::pure([2]);
/// let first_inst = circuit.append(PGate(2), 0, None).unwrap();
/// let second_inst = circuit.append(HGate(2), 0, None).unwrap();
///
/// let next_insts = circuit.next(first_inst);
/// assert_eq!(next_insts.len(), 1);
/// assert_eq!(next_insts[&Wire::quantum(0)], second_inst);
/// ```
pub fn next(&self, inst_id: InstructionId) -> HashMap<Wire, InstructionId> {
let cycle = self
.cycles
.get_from_id(inst_id.cycle())
.expect("Invalid instruction id.");
let wires = cycle.get_wires_from_id(inst_id.inner());
match wires {
Some(wires) => wires
.wires()
.filter_map(|wire| {
cycle.get_next(wire).map(|next_cycle_id| {
let next_cycle = self
.cycles
.get_from_id(next_cycle_id)
.expect("Expected cycle to exist.");
let next_inst_id = next_cycle
.get_id_from_wire(wire)
.expect("Expected there to be an instruction here?");
(wire, InstructionId::new(next_cycle_id, next_inst_id))
})
})
.collect(),
None => HashMap::new(),
}
}
/// Gather the points of the previous operations from the point of an
/// operation.
///
/// See [`QuditCircuit::next`] for more information.
pub fn prev(&self, inst_id: InstructionId) -> HashMap<Wire, InstructionId> {
let cycle = self
.cycles
.get_from_id(inst_id.cycle())
.expect("Invalid instruction id.");
let wires = cycle.get_wires_from_id(inst_id.inner());
match wires {
Some(wires) => wires
.wires()
.filter_map(|wire| {
cycle.get_prev(wire).map(|prev_cycle_id| {
let prev_cycle = self
.cycles
.get_from_id(prev_cycle_id)
.expect("Expected cycle to exist.");
let prev_inst_id = prev_cycle
.get_id_from_wire(wire)
.expect("Expected there to be an instruction here?");
(wire, InstructionId::new(prev_cycle_id, prev_inst_id))
})
})
.collect(),
None => HashMap::new(),
}
}
}