microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.23.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/npm/qsharp/src/compiler/events.ts

178lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4import { ShotResult, Dump, Result } from "./common.js";
5import { log } from "../log.js";
6import { IServiceEventTarget } from "../workers/common.js";
7
8// Create strongly typed compiler events
9export type QscEventData =
10 | { type: "Message"; detail: string }
11 | {
12 type: "DumpMachine";
13 detail: { state: Dump; stateLatex: string | null; qubitCount: number };
14 }
15 | { type: "Matrix"; detail: { matrix: number[][][]; matrixLatex: string } }
16 | { type: "Result"; detail: Result };
17
18export type QscEvents = Event & QscEventData;
19
20export type QscEvent<T extends QscEvents["type"]> = Extract<
21 QscEvents,
22 { type: T }
23>;
24
25// Strongly typed event target for compiler operations.
26export type IQscEventTarget = IServiceEventTarget<QscEventData>;
27
28// Convenience method that also provides type safety
29export function makeEvent<E extends QscEvents>(
30 type: E["type"],
31 detail: E["detail"],
32): E {
33 const event = new Event(type) as E;
34 event.detail = detail;
35 return event;
36}
37
38function makeResultObj(): ShotResult {
39 return { success: false, result: "", events: [] };
40}
41
42// The actual event target implementation adds one more event type
43// to notify the UI that the results should be refreshed.
44// This event does not come from the compiler service itself
45// so it's not exposed as part of QscEvents or IQscEventTarget.
46// Direct consumers of QscEventTarget can attach a listener for
47// this event.
48type QscUiEvents =
49 | QscEvents
50 | (Event & { type: "uiResultsRefresh"; detail: undefined });
51
52export class QscEventTarget implements IQscEventTarget {
53 private eventTarget = new EventTarget();
54 private results: ShotResult[] = [];
55 private shotActive = false;
56 private animationFrameId: any = 0;
57
58 // Overrides for the base EventTarget methods to limit to expected event types
59 addEventListener<T extends QscUiEvents["type"]>(
60 type: T,
61 listener: (event: Extract<QscEvents, { type: T }>) => void,
62 ): void {
63 this.eventTarget.addEventListener(type, listener as EventListener);
64 }
65
66 removeEventListener<T extends QscUiEvents["type"]>(
67 type: T,
68 listener: (event: Extract<QscEvents, { type: T }>) => void,
69 ): void {
70 this.eventTarget.removeEventListener(type, listener as EventListener);
71 }
72
73 dispatchEvent(event: QscUiEvents): boolean {
74 if (log.getLogLevel() >= 4) log.debug("Dispatching event: %o", event);
75 return this.eventTarget.dispatchEvent(event);
76 }
77
78 /**
79 * @param captureEvents Set to true if this instance should record events internally
80 */
81 constructor(captureEvents: boolean) {
82 if (captureEvents) {
83 this.addEventListener("Message", (ev) => this.onMessage(ev.detail));
84 this.addEventListener("DumpMachine", (ev) =>
85 this.onDumpMachine(ev.detail),
86 );
87 this.addEventListener("Result", (ev) => this.onResult(ev.detail));
88 this.addEventListener("Matrix", (ev) => this.onMatrix(ev.detail));
89 }
90 }
91
92 private onMessage(msg: string) {
93 this.ensureActiveShot();
94
95 const shotIdx = this.results.length - 1;
96 this.results[shotIdx].events.push({ type: "Message", message: msg });
97
98 this.queueUiRefresh();
99 }
100
101 private onMatrix(detail: { matrix: number[][][]; matrixLatex: string }) {
102 this.ensureActiveShot();
103
104 const shotIdx = this.results.length - 1;
105 this.results[shotIdx].events.push({
106 type: "Matrix",
107 matrix: detail.matrix,
108 matrixLatex: detail.matrixLatex,
109 });
110
111 this.queueUiRefresh();
112 }
113
114 private onDumpMachine(detail: {
115 state: Dump;
116 stateLatex: string | null;
117 qubitCount: number;
118 }) {
119 this.ensureActiveShot();
120
121 const shotIdx = this.results.length - 1;
122 this.results[shotIdx].events.push({
123 type: "DumpMachine",
124 state: detail.state,
125 stateLatex: detail.stateLatex,
126 qubitCount: detail.qubitCount,
127 });
128
129 this.queueUiRefresh();
130 }
131
132 private onResult(result: Result) {
133 this.ensureActiveShot();
134
135 const shotIdx = this.results.length - 1;
136
137 this.results[shotIdx].success = result.success;
138 this.results[shotIdx].result = result.value;
139 this.shotActive = false;
140
141 this.queueUiRefresh();
142 }
143
144 private ensureActiveShot() {
145 if (!this.shotActive) {
146 this.results.push(makeResultObj());
147 this.shotActive = true;
148 }
149 }
150
151 private queueUiRefresh() {
152 if (!this.animationFrameId) {
153 this.animationFrameId = setTimeout(() => {
154 this.onUiRefresh();
155 }, 50); // 20 fps is plenty for the rendering we do
156 }
157 }
158
159 private onUiRefresh() {
160 this.animationFrameId = 0;
161 const uiRefreshEvent = new Event("uiResultsRefresh") as QscUiEvents;
162 this.dispatchEvent(uiRefreshEvent);
163 }
164
165 getResults(): ShotResult[] {
166 return this.results;
167 }
168
169 resultCount(): number {
170 // May be one less than length if the last is still in flight
171 return this.shotActive ? this.results.length - 1 : this.results.length;
172 }
173
174 clearResults(): void {
175 this.results = [];
176 this.shotActive = false;
177 }
178}
179