1// Copyright 2021 The Cirq Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {expect} from 'chai';
16import {Symbol3D, SymbolInformation} from './types';
17import {BoxGate3DSymbol, Control3DSymbol, X3DSymbol} from './meshes';
18
19describe('Symbol3D', () => {
20  describe('with valid one qubit SymbolInformation objects', () => {
21    const symbols: SymbolInformation[] = [
22      {
23        wire_symbols: ['X'],
24        location_info: [{row: 0, col: 0}],
25        color_info: ['black'],
26        moment: 1,
27      },
28      {
29        wire_symbols: ['@'],
30        location_info: [{row: 1, col: 2}],
31        color_info: ['black'],
32        moment: 3,
33      },
34      {
35        wire_symbols: ['Y'],
36        location_info: [{row: 3, col: 2}],
37        color_info: ['purple'],
38        moment: 7,
39      },
40    ];
41
42    it('handles the X gate special case', () => {
43      const symbolObj = new Symbol3D(symbols[0]);
44      const xSymbol = symbolObj.children[0];
45      expect(xSymbol instanceof X3DSymbol).to.equal(true);
46    });
47
48    it('handles the control symbol special case', () => {
49      const symbolObj = new Symbol3D(symbols[1]);
50      const ctrlSymbol = symbolObj.children[0];
51      expect(ctrlSymbol instanceof Control3DSymbol).to.equal(true);
52    });
53
54    it('handles an arbitrary symbol with a box', () => {
55      const symbolObj = new Symbol3D(symbols[2]);
56      const boxSymbol = symbolObj.children[0];
57      expect(boxSymbol instanceof BoxGate3DSymbol).to.equal(true);
58    });
59
60    it('builds every symbol in the correct location on the scene', () => {
61      const expectedRows = [0, 1, 3];
62      const expectedCols = [0, 2, 2];
63      const expectedMoments = [1, 3, 7];
64      symbols.forEach((value, index) => {
65        const symbol = new Symbol3D(value).children[0];
66        expect(symbol.position.x).to.equal(expectedRows[index]);
67        expect(symbol.position.y).to.equal(expectedMoments[index]);
68        expect(symbol.position.z).to.equal(expectedCols[index]);
69      });
70    });
71  });
72
73  describe('with valid multi-qubit SymbolInformation objects', () => {
74    const symbols: SymbolInformation[] = [
75      {
76        wire_symbols: ['@', 'X'],
77        location_info: [
78          {row: 0, col: 0},
79          {row: 0, col: 1},
80        ],
81        color_info: ['black', 'black'],
82        moment: 1,
83      },
84      {
85        wire_symbols: ['×', '×'],
86        location_info: [
87          {row: 0, col: 0},
88          {row: 0, col: 1},
89        ],
90        color_info: ['black', 'black'],
91        moment: 3,
92      },
93      {
94        wire_symbols: ['iSWAP', 'iSWAP'],
95        location_info: [
96          {row: 3, col: 2},
97          {row: 3, col: 3},
98        ],
99        color_info: ['#d3d3d3', '#d3d3d3'],
100        moment: 7,
101      },
102      {
103        wire_symbols: ['@', '@', 'X'],
104        location_info: [
105          {row: 0, col: 0},
106          {row: 0, col: 1},
107          {row: 0, col: 2},
108        ],
109        color_info: ['black', 'black', 'black'],
110        moment: 1,
111      },
112    ];
113
114    it('handles a control symbol and an X gate (CNOT)', () => {
115      const symbolObj = new Symbol3D(symbols[0]);
116
117      const ctrlSymbol = symbolObj.children.find(
118        child => child.constructor.name === 'Control3DSymbol'
119      );
120      expect(ctrlSymbol).to.not.equal(undefined);
121      expect(ctrlSymbol?.position.x).to.equal(0);
122      expect(ctrlSymbol?.position.z).to.equal(0);
123      expect(ctrlSymbol?.position.y).to.equal(1);
124
125      const xSymbol = symbolObj.children.find(
126        child => child.constructor.name === 'X3DSymbol'
127      );
128      expect(xSymbol).to.not.equal(undefined);
129      expect(xSymbol?.position.x).to.equal(0);
130      expect(xSymbol?.position.z).to.equal(1);
131      expect(xSymbol?.position.y).to.equal(1);
132
133      const connectionLine = symbolObj.children.find(
134        child => child.constructor.name === 'ConnectionLine'
135      );
136
137      expect(connectionLine).to.not.equal(undefined);
138    });
139
140    it('handles a two Swap3DSymbol objects correctly (SWAP)', () => {
141      const symbolObj = new Symbol3D(symbols[1]);
142
143      const boxSymbols = symbolObj.children.filter(
144        child => child.constructor.name === 'Swap3DSymbol'
145      );
146      expect(boxSymbols.length).to.equal(2);
147
148      const expectedRows = [0, 0];
149      const expectedCols = [0, 1];
150      boxSymbols.forEach((value, index) => {
151        expect(value.position.x).to.equal(expectedRows[index]);
152        expect(value.position.z).to.equal(expectedCols[index]);
153        expect(value.position.y).to.equal(3);
154      });
155
156      const connectionLine = symbolObj.children.find(
157        child => child.constructor.name === 'ConnectionLine'
158      );
159      expect(connectionLine).to.not.equal(undefined);
160    });
161
162    it('handles a two BoxGate3DSymbol objects correctly (iSWAP)', () => {
163      const symbolObj = new Symbol3D(symbols[2]);
164
165      const boxSymbols = symbolObj.children.filter(
166        child => child.constructor.name === 'BoxGate3DSymbol'
167      );
168      expect(boxSymbols.length).to.equal(2);
169
170      const expectedRows = [3, 3];
171      const expectedCols = [2, 3];
172      boxSymbols.forEach((value, index) => {
173        expect(value.position.x).to.equal(expectedRows[index]);
174        expect(value.position.z).to.equal(expectedCols[index]);
175        expect(value.position.y).to.equal(7);
176      });
177
178      const connectionLine = symbolObj.children.find(
179        child => child.constructor.name === 'ConnectionLine'
180      );
181      expect(connectionLine).to.not.equal(undefined);
182    });
183
184    it('handles two control symbols and an X gate correctly (Toffoli)', () => {
185      const symbolObj = new Symbol3D(symbols[3]);
186
187      const boxSymbols = symbolObj.children.filter(
188        child => child.constructor.name === 'Control3DSymbol'
189      );
190      expect(boxSymbols.length).to.equal(2);
191
192      const xSymbol = symbolObj.children.find(
193        child => child.constructor.name === 'X3DSymbol'
194      );
195      expect(xSymbol).to.not.equal(undefined);
196
197      const expectedRows = [0, 0, 0];
198      const expectedCols = [0, 1, 2];
199      boxSymbols.forEach((value, index) => {
200        expect(value.position.x).to.equal(expectedRows[index]);
201        expect(value.position.z).to.equal(expectedCols[index]);
202        expect(value.position.y).to.equal(1);
203      });
204
205      const connectionLines = symbolObj.children.filter(
206        child => child.constructor.name === 'ConnectionLine'
207      );
208      expect(connectionLines.length).to.equal(2);
209    });
210  });
211});
212