microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
579fb3b830d056df6afed7eede31204e61589ff9

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/npm/qsharp/src/data-structures/circuit.ts

275lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT license.
3
4import { isRegister, Register } from "./register.js";
5
6/**
7 * Current format version.
8 */
9export const CURRENT_VERSION = 1;
10
11export interface CircuitGroup {
12 circuits: Circuit[];
13 version: number;
14}
15
16/**
17 * Runtime check: is this a valid CircuitGroup?
18 */
19export function isCircuitGroup(obj: any): obj is CircuitGroup {
20 return (
21 obj &&
22 typeof obj === "object" &&
23 typeof obj.version === "number" &&
24 Array.isArray(obj.circuits) &&
25 obj.circuits.length > 0 &&
26 obj.circuits.every(isCircuit)
27 );
28}
29
30/**
31 * Circuit to be visualized.
32 */
33export interface Circuit {
34 /** Array of qubit resources. */
35 qubits: Qubit[];
36 componentGrid: ComponentGrid;
37}
38
39/**
40 * Runtime check: is this a valid Circuit?
41 */
42export function isCircuit(obj: any): obj is Circuit {
43 return (
44 obj &&
45 typeof obj === "object" &&
46 Array.isArray(obj.qubits) &&
47 obj.qubits.every(isQubit) &&
48 Array.isArray(obj.componentGrid) &&
49 obj.componentGrid.every(isColumn)
50 );
51}
52
53export type ComponentGrid = Column[];
54
55export interface Column {
56 components: Component[];
57}
58
59/**
60 * Runtime check: is this a valid Column?
61 */
62export function isColumn(obj: any): obj is Column {
63 return (
64 obj &&
65 typeof obj === "object" &&
66 Array.isArray(obj.components) &&
67 obj.components.every(isOperation)
68 );
69}
70
71/**
72 * Represents a component of a circuit. Currently, the only component is an operation.
73 * In the future, this may be extended to include other components.
74 */
75export type Component = Operation;
76
77/**
78 * Represents a unique qubit resource bit.
79 */
80export interface Qubit {
81 /** Qubit ID. */
82 id: number;
83 /** Number of measurement results associated to the qubit. */
84 numResults?: number;
85 /** Declaration locations in the source code. */
86 declarations?: SourceLocation[];
87}
88
89/**
90 * Runtime check: is this a valid Qubit?
91 */
92export function isQubit(obj: any): obj is Qubit {
93 return (
94 obj &&
95 typeof obj === "object" &&
96 typeof obj.id === "number" &&
97 // numResults is optional, but if present must be a number
98 (obj.numResults === undefined || typeof obj.numResults === "number")
99 );
100}
101
102/**
103 * Base type for operations.
104 */
105export interface BaseOperation {
106 /** Gate label. */
107 gate: string;
108 /** Formatted gate arguments. */
109 args?: string[];
110 /** The parameters expected for the operation. */
111 params?: Parameter[];
112 /** Nested operations within this operation. */
113 children?: ComponentGrid;
114
115 /** Custom data attributes to attach to gate element.
116 Note that this is never written to file, so it is not part of the circuit schema */
117 dataAttributes?: DataAttributes;
118
119 /** Whether gate is a classically controlled operation. */
120 isConditional?: boolean;
121
122 /** Not written to file */
123 metadata?: Metadata;
124}
125
126/**
127 * Runtime check: is this a valid BaseOperation?
128 */
129function isBaseOperation(obj: any): obj is BaseOperation {
130 return (
131 obj &&
132 typeof obj === "object" &&
133 typeof obj.gate === "string" &&
134 // args is optional, but if present must be an array of strings
135 (obj.args === undefined ||
136 (Array.isArray(obj.args) &&
137 obj.args.every((arg: any) => typeof arg === "string"))) &&
138 // params is optional, but if present must be an array of Parameter
139 (obj.params === undefined ||
140 (Array.isArray(obj.params) && obj.params.every(isParameter))) &&
141 // children is optional, but if present must be a ComponentGrid
142 (obj.children === undefined ||
143 (Array.isArray(obj.children) && obj.children.every(isColumn))) &&
144 // dataAttributes is optional, but if present must be an object with string values
145 (obj.dataAttributes === undefined ||
146 (typeof obj.dataAttributes === "object" &&
147 obj.dataAttributes !== null &&
148 Object.values(obj.dataAttributes).every(
149 (val) => typeof val === "string",
150 ))) &&
151 // isConditional is optional, but if present must be boolean
152 (obj.isConditional === undefined || typeof obj.isConditional === "boolean")
153 );
154}
155
156/**
157 * Represents a measurement operation and the registers it acts on.
158 */
159export interface Measurement extends BaseOperation {
160 /** Discriminator for the Operation type */
161 kind: "measurement";
162 /** The qubit registers the gate measures. */
163 qubits: Register[];
164 /** The classical registers the gate writes to. */
165 results: Register[];
166}
167
168/**
169 * Represents a unitary operation and the registers it acts on.
170 */
171export interface Unitary extends BaseOperation {
172 /** Discriminator for the Operation type */
173 kind: "unitary";
174 /** Target registers the gate acts on. */
175 targets: Register[];
176 /** Control registers the gate acts on. */
177 controls?: Register[];
178 /** Whether gate is an adjoint operation. */
179 isAdjoint?: boolean;
180}
181
182/**
183 * Represents a gate that sets its targets to a specific state.
184 */
185export interface Ket extends BaseOperation {
186 /** Discriminator for the Operation type */
187 kind: "ket";
188 /** Target registers the gate acts on. */
189 targets: Register[];
190}
191
192/**
193 * Union type for operations.
194 */
195export type Operation = Unitary | Measurement | Ket;
196
197/**
198 * Runtime check: is this a valid Operation?
199 */
200export function isOperation(obj: any): obj is Operation {
201 if (!isBaseOperation(obj)) return false;
202 // Re-cast to any so we can check discriminated fields without narrowing
203 const op: any = obj;
204 if (op.kind === undefined || typeof op.kind !== "string") return false;
205 switch (op.kind) {
206 case "unitary":
207 return (
208 Array.isArray(op.targets) &&
209 op.targets.every(isRegister) &&
210 // controls is optional
211 (op.controls === undefined ||
212 (Array.isArray(op.controls) && op.controls.every(isRegister))) &&
213 // isAdjoint is optional
214 (op.isAdjoint === undefined || typeof op.isAdjoint === "boolean")
215 );
216 case "measurement":
217 return (
218 Array.isArray(op.qubits) &&
219 op.qubits.every(isRegister) &&
220 Array.isArray(op.results) &&
221 op.results.every(isRegister)
222 );
223 case "ket":
224 return Array.isArray(op.targets) && op.targets.every(isRegister);
225 default:
226 return false;
227 }
228}
229
230/**
231 * A parameter for an operation.
232 */
233export interface Parameter {
234 /** Parameter name. */
235 name: string;
236 /** Parameter's Q# type. */
237 type: string;
238}
239
240/**
241 * Runtime check: is this a valid Parameter?
242 */
243export function isParameter(obj: any): obj is Parameter {
244 return (
245 obj &&
246 typeof obj === "object" &&
247 typeof obj.name === "string" &&
248 typeof obj.type === "string"
249 );
250}
251
252/**
253 * Custom data attributes (e.g. data-{attr}="{val}")
254 */
255export interface DataAttributes {
256 [attr: string]: string;
257}
258
259export interface SourceLocation {
260 file: string;
261 line: number;
262 column: number;
263}
264
265export interface Metadata {
266 source?: SourceLocation;
267 scopeLocation?: SourceLocation;
268 /**
269 * For a classically controlled operation,
270 * this maps control registers to the measurement result
271 * IDs. Unlike the `result` field in `Register`, which are
272 * specific to the qubit, these IDs are global across the circuit.
273 */
274 controlResultIds?: [Register, number][];
275}
276