microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
minestarks/circuit-magic

Branches

Tags

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

Clone

HTTPS

Download ZIP

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

272lines · 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}
86
87/**
88 * Runtime check: is this a valid Qubit?
89 */
90export function isQubit(obj: any): obj is Qubit {
91 return (
92 obj &&
93 typeof obj === "object" &&
94 typeof obj.id === "number" &&
95 // numResults is optional, but if present must be a number
96 (obj.numResults === undefined || typeof obj.numResults === "number")
97 );
98}
99
100/**
101 * Base type for operations.
102 */
103export interface BaseOperation {
104 /** Gate label. */
105 gate: string;
106 /** Formatted gate arguments. */
107 args?: string[];
108 /** The parameters expected for the operation. */
109 params?: Parameter[];
110 /** Nested operations within this operation. */
111 children?: ComponentGrid;
112
113 /** Custom data attributes to attach to gate element.
114 Note that this is never written to file, so it is not part of the circuit schema */
115 dataAttributes?: DataAttributes;
116
117 /** Whether gate is a conditional operation. */
118 isConditional?: boolean;
119 /** Specify conditions on when to render operation. */
120 conditionalRender?: ConditionalRender;
121}
122
123/**
124 * Runtime check: is this a valid BaseOperation?
125 */
126function isBaseOperation(obj: any): obj is BaseOperation {
127 return (
128 obj &&
129 typeof obj === "object" &&
130 typeof obj.gate === "string" &&
131 // args is optional, but if present must be an array of strings
132 (obj.args === undefined ||
133 (Array.isArray(obj.args) &&
134 obj.args.every((arg: any) => typeof arg === "string"))) &&
135 // params is optional, but if present must be an array of Parameter
136 (obj.params === undefined ||
137 (Array.isArray(obj.params) && obj.params.every(isParameter))) &&
138 // children is optional, but if present must be a ComponentGrid
139 (obj.children === undefined ||
140 (Array.isArray(obj.children) && obj.children.every(isColumn))) &&
141 // dataAttributes is optional, but if present must be an object with string values
142 (obj.dataAttributes === undefined ||
143 (typeof obj.dataAttributes === "object" &&
144 obj.dataAttributes !== null &&
145 Object.values(obj.dataAttributes).every(
146 (val) => typeof val === "string",
147 ))) &&
148 // isConditional is optional, but if present must be boolean
149 (obj.isConditional === undefined ||
150 typeof obj.isConditional === "boolean") &&
151 // conditionalRender is optional, but if present must be a valid enum value
152 (obj.conditionalRender === undefined ||
153 Object.values(ConditionalRender).includes(obj.conditionalRender))
154 );
155}
156
157/**
158 * Represents a measurement operation and the registers it acts on.
159 */
160export interface Measurement extends BaseOperation {
161 /** Discriminator for the Operation type */
162 kind: "measurement";
163 /** The qubit registers the gate measures. */
164 qubits: Register[];
165 /** The classical registers the gate writes to. */
166 results: Register[];
167}
168
169/**
170 * Represents a unitary operation and the registers it acts on.
171 */
172export interface Unitary extends BaseOperation {
173 /** Discriminator for the Operation type */
174 kind: "unitary";
175 /** Target registers the gate acts on. */
176 targets: Register[];
177 /** Control registers the gate acts on. */
178 controls?: Register[];
179 /** Whether gate is an adjoint operation. */
180 isAdjoint?: boolean;
181}
182
183/**
184 * Represents a gate that sets its targets to a specific state.
185 */
186export interface Ket extends BaseOperation {
187 /** Discriminator for the Operation type */
188 kind: "ket";
189 /** Target registers the gate acts on. */
190 targets: Register[];
191}
192
193/**
194 * Union type for operations.
195 */
196export type Operation = Unitary | Measurement | Ket;
197
198/**
199 * Runtime check: is this a valid Operation?
200 */
201export function isOperation(obj: any): obj is Operation {
202 if (!isBaseOperation(obj)) return false;
203 // Re-cast to any so we can check discriminated fields without narrowing
204 const op: any = obj;
205 if (op.kind === undefined || typeof op.kind !== "string") return false;
206 switch (op.kind) {
207 case "unitary":
208 return (
209 Array.isArray(op.targets) &&
210 op.targets.every(isRegister) &&
211 // controls is optional
212 (op.controls === undefined ||
213 (Array.isArray(op.controls) && op.controls.every(isRegister))) &&
214 // isAdjoint is optional
215 (op.isAdjoint === undefined || typeof op.isAdjoint === "boolean")
216 );
217 case "measurement":
218 return (
219 Array.isArray(op.qubits) &&
220 op.qubits.every(isRegister) &&
221 Array.isArray(op.results) &&
222 op.results.every(isRegister)
223 );
224 case "ket":
225 return Array.isArray(op.targets) && op.targets.every(isRegister);
226 default:
227 return false;
228 }
229}
230
231/**
232 * A parameter for an operation.
233 */
234export interface Parameter {
235 /** Parameter name. */
236 name: string;
237 /** Parameter's Q# type. */
238 type: string;
239}
240
241/**
242 * Runtime check: is this a valid Parameter?
243 */
244export function isParameter(obj: any): obj is Parameter {
245 return (
246 obj &&
247 typeof obj === "object" &&
248 typeof obj.name === "string" &&
249 typeof obj.type === "string"
250 );
251}
252
253/**
254 * Conditions on when to render the given operation.
255 */
256export enum ConditionalRender {
257 /** Always rendered. */
258 Always,
259 /** Render classically-controlled operation when measurement is a zero. */
260 OnZero,
261 /** Render classically-controlled operation when measurement is a one. */
262 OnOne,
263 /** Render operation as a group of its nested operations. */
264 AsGroup,
265}
266
267/**
268 * Custom data attributes (e.g. data-{attr}="{val}")
269 */
270export interface DataAttributes {
271 [attr: string]: string;
272}
273