q1tsim/export/
latex.rs

1// Copyright 2019 Q1t BV
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//    http://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
15/// Structure to build up contents of LaTeX export
16///
17/// Struct `LatexExportState` is used to build up the matrix containing the
18/// Qcircuit code for the export of a `Circuit` to LaTeX.
19pub struct LatexExportState
20{
21    // Variables relating to the circuit
22
23    /// The number of quantum bits in the circuit.
24    nr_qbits: usize,
25    /// The number of classical bits in the circuit.
26    nr_cbits: usize,
27
28    // Settings for output
29
30    /// If `true` (the default), add initialization of the bits to the circuit.
31    add_init: bool,
32    /// If `true` (the default), composite gates are expanded into primitive
33    /// gates in the export.
34    expand_composite: bool,
35
36    // Runtime variables
37
38    /// Matrix containing LaTex code for each individual gate. Every row in
39    /// the matrix corresponds to a column in the exported circuit.
40    matrix: Vec<Vec<Option<String>>>,
41    /// Vector containing which fields in the last row are currently occupied.
42    /// Unoccupied fields can be used, if a gate operates on an occupied field,
43    /// a new row must be added.
44    in_use: Vec<bool>,
45    /// Whether the gate currently being exported is being controlled or not.
46    /// This has an impact on the representation of certain gates, e.g. the `X`
47    /// gate which is normally represented as a boxed X character, but is
48    /// represented by a circled plus (⊕) when it is controlled.
49    controlled: bool,
50    /// When the state is currently in the process of drawing an operation
51    /// operating on a range of bits with possible gaps, this holds the minimum
52    /// and maximum bit index of said range.
53    reserved_ranges: Vec<(usize, usize)>,
54    /// start and end row, and nr of iterations, of static loops.
55    loops: Vec<(usize, usize, usize)>,
56    /// Start index and nr of iterations of currently unfinished static loops.
57    /// Vector because noops may be nested.
58    open_loops: Vec<(usize, usize)>
59}
60
61impl LatexExportState
62{
63    /// Create a new LatexExportState
64    ///
65    /// Create a new `LatexExportState`, for a circuit with `nr_qbits` quantum
66    /// bits and `nr_cbits` classical bits.
67    pub fn new(nr_qbits: usize, nr_cbits: usize) -> Self
68    {
69        LatexExportState
70        {
71            nr_qbits: nr_qbits,
72            nr_cbits: nr_cbits,
73            add_init: true,
74            expand_composite: true,
75            matrix: vec![],
76            in_use: vec![true; nr_qbits + nr_cbits],
77            controlled: false,
78            reserved_ranges: vec![],
79            loops: vec![],
80            open_loops: vec![]
81        }
82    }
83
84    /// The total number of bits (quantum or classical) in the circuit.
85    fn total_nr_bits(&self) -> usize
86    {
87        self.nr_qbits + self.nr_cbits
88    }
89
90    /// Add a new column.
91    ///
92    /// Add a new column to the export. Used when a new gate operates on a bit
93    /// that is already in use.
94    fn add_column(&mut self)
95    {
96        let nr_bits = self.total_nr_bits();
97        self.matrix.push(vec![None; nr_bits]);
98        self.in_use.clear();
99        self.in_use.resize(nr_bits, false);
100    }
101
102    fn get_bit_indices(&self, qbits: &[usize], cbits: Option<&[usize]>)
103        -> crate::error::Result<Vec<usize>>
104    {
105        if let Some(&bit) = qbits.iter().find(|&&b| b >= self.nr_qbits)
106        {
107            return Err(crate::error::Error::InvalidQBit(bit));
108        }
109
110        let mut bits = qbits.to_vec();
111        if let Some(cbs) = cbits
112        {
113            if let Some(&bit) = cbs.iter().find(|&&b| b >= self.nr_cbits)
114            {
115                return Err(crate::error::Error::InvalidCBit(bit));
116            }
117            bits.extend(cbs.iter().map(|&b| self.nr_qbits + b));
118        }
119
120        Ok(bits)
121    }
122
123    /// Ensure that fields are free.
124    ///
125    /// Ensure that the fields for the bits in `qbits` and (optionally) `cbits`
126    /// are currently unoccupied. If not, add a new column to the export.
127    pub fn reserve(&mut self, qbits: &[usize], cbits: Option<&[usize]>)
128        -> crate::error::Result<()>
129    {
130        let bits = self.get_bit_indices(qbits, cbits)?;
131        if bits.iter().any(|&b| self.in_use[b])
132        {
133            self.add_column();
134        }
135
136        Ok(())
137    }
138
139    /// Ensure all fields are free.
140    ///
141    /// Ensure that the last column is currently fully empty. If not, add a new
142    /// column to the export.
143    fn reserve_all(&mut self)
144    {
145        if self.in_use.contains(&true)
146        {
147            self.add_column();
148        }
149    }
150
151    /// Ensure that fields are free.
152    ///
153    /// Ensure that the fields for the bits in `qbits` and (optionally) `cbits`,
154    /// as well as all field in the range between the minimum and maximum bit,
155    /// are currently unoccupied. If not, add a new column to the export.
156    pub fn start_range_op(&mut self, qbits: &[usize], cbits: Option<&[usize]>)
157        -> crate::error::Result<()>
158    {
159        let bits = self.get_bit_indices(qbits, cbits)?;
160        if let Some(&first) = bits.iter().min()
161        {
162            let last = *bits.iter().max().unwrap();
163
164            if self.reserved_ranges.is_empty()
165            {
166                if self.in_use[first..=last].contains(&true)
167                {
168                    self.add_column();
169                }
170                self.reserved_ranges.push((first, last));
171            }
172            else
173            {
174                let &(outer_first, outer_last) = self.reserved_ranges.last().unwrap();
175                if outer_first <= first && outer_last >= last
176                {
177                    self.reserved_ranges.push((first, last));
178                }
179                else
180                {
181                    return Err(crate::error::Error::from(crate::error::ExportError::RangeAlreadyOpen));
182                }
183            }
184
185        }
186
187        Ok(())
188    }
189
190    /// Mark fields as in use.
191    ///
192    /// Mark the fields in the fields in the range last opened by
193    /// `start_range_op()` as in use, and close the range.
194    pub fn end_range_op(&mut self)
195    {
196        if let Some((first, last)) = self.reserved_ranges.pop()
197        {
198            for bit in first..=last
199            {
200                self.in_use[bit] = true;
201            }
202        }
203    }
204
205    /// Set the contents of a field
206    ///
207    /// Set the contents of the field corresponding to bit `bit` to the LaTeX
208    /// code in `contents`.
209    pub fn set_field(&mut self, bit: usize, contents: String) -> crate::error::Result<()>
210    {
211        if self.reserved_ranges.is_empty()
212        {
213            self.reserve(&[bit], None)?;
214        }
215
216        let col = self.matrix.last_mut().unwrap();
217        col[bit] = Some(contents);
218        self.in_use[bit] = true;
219        Ok(())
220    }
221
222    /// Add a measurement
223    ///
224    /// Add a measurement of quantum bit `qbit` to classical bit `cbit` in basis
225    /// `basis` to the export. If `basis` is `None`, no basis string is drawn in
226    /// the measurement.
227    pub fn set_measurement(&mut self, qbit: usize, cbit: usize, basis: Option<&str>)
228        -> crate::error::Result<()>
229    {
230        let cbit_idx = self.nr_qbits + cbit;
231        self.start_range_op(&[qbit], Some(&[cbit]))?;
232        let meter = if let Some(b) = basis
233            {
234                format!(r"\meterB{{{}}}", b)
235            }
236            else
237            {
238                String::from(r"\meter")
239            };
240        self.set_field(qbit, meter)?;
241        self.set_field(cbit_idx, format!(r"\cw \cwx[{}]", qbit as isize - cbit_idx as isize))?;
242        self.end_range_op();
243
244        Ok(())
245    }
246
247    /// Add a reset
248    ///
249    /// Add the reset of quantum bit `qbit` to the export.
250    pub fn set_reset(&mut self, qbit: usize) -> crate::error::Result<()>
251    {
252        self.set_field(qbit, String::from(r"\push{~\ket{0}~} \ar @{|-{}} [0,-1]"))
253    }
254
255    /// Add classical control
256    ///
257    /// Add the control of an operation on quantum bits `qbits` by classical
258    /// bits control to the export state. This function only adds the control
259    /// part, the actual quantum operation should be drawn elsewhere. The bits
260    /// in `control` make up a register, whose value should match `target`.
261    /// The first bit in `control` corresponds to the least significant bit of
262    /// `target`, the last bit in `control` to the most significant bit.
263    pub fn set_condition(&mut self, control: &[usize], target: u64, qbits: &[usize])
264        -> crate::error::Result<()>
265    {
266        if let Some(&bit) = qbits.iter().find(|&&b| b >= self.nr_qbits)
267        {
268            return Err(crate::error::Error::InvalidQBit(bit));
269        }
270        if let Some(&bit) = control.iter().find(|&&b| b >= self.nr_cbits)
271        {
272            return Err(crate::error::Error::InvalidCBit(bit));
273        }
274
275        if qbits.is_empty()
276        {
277            return Ok(());
278        }
279
280        let mut pbit = *qbits.iter().max().unwrap();
281        let mut bp: Vec<(usize, usize)> = control.iter().enumerate()
282            .map(|(pos, &idx)| (self.nr_qbits + idx, pos))
283            .collect();
284        bp.sort();
285        for (bit, pos) in bp
286        {
287            let ctrl = if (target & (1 << pos)) == 0 { r"\cctrlo" } else { r"\cctrl" };
288            self.set_field(bit, format!("{}{{{}}}", ctrl, pbit as isize - bit as isize))?;
289            pbit = bit;
290        }
291
292        Ok(())
293    }
294
295    /// Add a simple block gate
296    ///
297    /// Add a gate with description `desc` operating on qubits `qbits` as a
298    /// simple box containing the description. If the gate opertes on mutiple
299    /// disjoint ranges of qbits, it is drawn using mutiple boxes connected by
300    /// wires.
301    pub fn add_block_gate(&mut self, qbits: &[usize], desc: &str) -> crate::error::Result<()>
302    {
303        let ranges = crate::support::get_ranges(qbits);
304        if !ranges.is_empty()
305        {
306            self.start_range_op(qbits, None)?;
307
308            let (first, last) = ranges[0];
309            if last == first
310            {
311                self.set_field(first, format!(r"\gate{{{}}}", desc))?;
312            }
313            else
314            {
315                self.set_field(first,
316                    format!(r"\multigate{{{}}}{{{}}}", last-first, desc))?;
317                for bit in first+1..last+1
318                {
319                    self.set_field(bit, format!(r"\ghost{{{}}}", desc))?;
320                }
321            }
322
323            let mut prev_last = last;
324            for &(first, last) in ranges[1..].iter()
325            {
326                if last == first
327                {
328                    self.set_field(first,
329                        format!(r"\gate{{{}}} \qwx[{}]", desc, prev_last as isize - first as isize))?;
330                }
331                else
332                {
333                    self.set_field(first,
334                        format!(r"\multigate{{{}}}{{{}}} \qwx[{}]",
335                            last - first, desc, prev_last as isize - first as isize))?;
336                    for bit in first+1..last+1
337                    {
338                        self.set_field(bit, format!(r"\ghost{{{}}}", desc))?;
339                    }
340                }
341
342                prev_last = last;
343            }
344
345            self.end_range_op();
346        }
347
348        Ok(())
349    }
350
351    /// Open a loop
352    ///
353    /// Open a loop of `count` ieterations at the current row in the export
354    /// state. This loop should later be closed by a call to `end_loop()`, at
355    /// which point the loop will be added to the export state.
356    pub fn start_loop(&mut self, count: usize)
357    {
358        self.reserve_all();
359        self.open_loops.push((self.matrix.len() - 1, count));
360    }
361
362    /// Close a loop
363    ///
364    /// Close the loop opened last by a call to `start_loop()`.
365    pub fn end_loop(&mut self) -> crate::error::Result<()>
366    {
367        if let Some((start, count)) = self.open_loops.pop()
368        {
369            let end = self.matrix.len() - 1;
370            self.loops.push((start, end, count));
371            self.reserve_all();
372            Ok(())
373        }
374        else
375        {
376            Err(crate::error::Error::from(crate::error::ExportError::CantCloseLoop))
377        }
378    }
379
380    /// Add dots
381    ///
382    /// This function adds the string in `label` in the middle of the range of
383    /// qbits starting at `bit` and going `count` bits down. This is usually
384    /// used to add the dots used to indicate a repeated subcircuit in loops.
385    pub fn add_cds(&mut self, bit: usize, count: usize, label: &str) -> crate::error::Result<()>
386    {
387        self.reserve_all();
388        self.set_field(bit, format!(r"\cds{{{}}}{{{}}}", count, label))?;
389        self.reserve_all();
390        Ok(())
391    }
392
393    /// Add a barrier
394    ///
395    /// Add a barrier for the quantum bits in `qbits`. Note that the placement
396    /// of barriers may sometimes be off because the spacing between elements
397    /// is not constant. It may therefore need some manual adjustment.
398    pub fn set_barrier(&mut self, qbits: &[usize]) -> crate::error::Result<()>
399    {
400        if let Some(&bit) = qbits.iter().find(|&&b| b >= self.nr_qbits)
401        {
402            return Err(crate::error::Error::InvalidQBit(bit));
403        }
404
405        let ranges = crate::support::get_ranges(qbits);
406
407        self.add_column();
408        for (first, last) in ranges
409        {
410            self.set_field(first, format!(r"\qw \barrier{{{}}}", last - first))?;
411        }
412
413        Ok(())
414    }
415
416    /// Export to LaTeX
417    ///
418    /// This code exports the matrix that was built up in this state to LaTeX
419    /// code. It uses the qcircuit package to do so.
420    pub fn code(&self) -> String
421    {
422        let mut res = String::from("\\Qcircuit @C=1em @R=.7em {\n");
423
424        if !self.loops.is_empty()
425        {
426            let mut prev_idx = 0;
427            res += r"    & ";
428            for (start, end, count) in self.loops.iter()
429            {
430                res += r"& ".repeat(start - prev_idx).as_str();
431                res += format!("\\mbox{{}} \\POS\"{},{}\".\"{},{}\".\"{},{}\".\"{},{}\"!C*+<.7em>\\frm{{^\\}}}},+U*++!D{{{}\\times}}",
432                    2, start+2, 2, start+2, /*self.total_nr_bits()+*/2, end+2,
433                    /*self.total_nr_bits()+*/2, end+2, count).as_str();
434                prev_idx = *start;
435            }
436            res += "\\\\\n";
437
438            res += r"    ";
439            res += r"& ".repeat(self.matrix.len()).as_str();
440            res += "\\\\\n";
441        }
442
443        let last_col_used = self.in_use.contains(&true);
444        for i in 0..self.total_nr_bits()
445        {
446            if self.add_init
447            {
448                if i < self.nr_qbits
449                {
450                    res += r"    \lstick{\ket{0}}";
451                }
452                else
453                {
454                    res += r"    \lstick{0}";
455                }
456            }
457            else
458            {
459                res += r"    ";
460            }
461            for row in self.matrix.iter()
462            {
463                res += " & ";
464                if let Some(ref s) = row[i]
465                {
466                    res += s.as_str();
467                }
468                else if i < self.nr_qbits
469                {
470                    res += r"\qw";
471                }
472                else
473                {
474                    res += r"\cw";
475                }
476            }
477
478            if last_col_used
479            {
480                res += r" & ";
481                res += if i < self.nr_qbits { r"\qw" } else { r"\cw" };
482            }
483            res += " \\\\\n";
484        }
485        res += "}\n";
486
487        res
488    }
489
490    /// Set whether gates are controlled
491    ///
492    /// This sets the option to draw gates in their normal layout
493    /// (`controlled = false`) or in their controlled layout (when
494    /// `controlled = true`). This can make a difference for e.g. the X gate,
495    /// which is drawn as a boxed X character normally, but as an exclusive
496    /// or symbol (⊕) when used in a `CX` gate.
497    pub fn set_controlled(&mut self, controlled: bool) -> bool
498    {
499        let res = self.controlled;
500        self.controlled = controlled;
501        res
502    }
503
504    /// Return whether gates should currently be drawn normally, or in their
505    /// controlled form.
506    pub fn is_controlled(&self) -> bool
507    {
508        self.controlled
509    }
510
511    /// Set whether to expand composite gates.
512    ///
513    /// Set whether composite gates should be drawn as individual components.
514    /// If `expand` is `true`, composite gates are drawn by drawing their
515    /// components. If `expand` is false, composite gates are drawn as a single
516    /// block gate.
517    pub fn set_expand_composite(&mut self, expand: bool)
518    {
519        self.expand_composite = expand;
520    }
521
522    /// Whether to expand composite gates.
523    ///
524    /// Return whether composite gates should be drawn as individual components
525    /// (in which case `true` is returned), or as a single, possibly multi-bit,
526    /// operation (when the result is `false`).
527    pub fn expand_composite(&self) -> bool
528    {
529        self.expand_composite
530    }
531
532    /// Set whether to add initialization strings
533    ///
534    /// When `add_init` is `true`, initialization strings are added to the
535    /// bits, when `false` they are omitted.
536    pub fn set_add_init(&mut self, add_init: bool)
537    {
538        self.add_init = add_init;
539    }
540}
541
542/// Trait for gates that can be drawn in LaTeX
543pub trait Latex: crate::gates::Gate
544{
545    /// Add this gate to the export state.
546    ///
547    /// Add the execution of this gate on the bits in `bits`, to the export
548    /// state `state`. The default implementation returns a NotImplemented error.
549    fn latex(&self, bits: &[usize], state: &mut LatexExportState)
550        -> crate::error::Result<()>
551    {
552        self.check_nr_bits(bits.len())?;
553        state.add_block_gate(bits, self.description())
554    }
555}
556
557#[cfg(test)]
558mod tests
559{
560    use super::{LatexExportState, Latex};
561
562    struct NoLatexGate;
563
564    impl crate::gates::Gate for NoLatexGate
565    {
566        fn cost(&self) -> f64 { 0.0 }
567        fn description(&self) -> &str { "NLG" }
568        fn nr_affected_bits(&self) -> usize { 3 }
569        fn matrix(&self) -> crate::cmatrix::CMatrix { unimplemented!() }
570    }
571    impl Latex for NoLatexGate {}
572
573    #[test]
574    fn test_new()
575    {
576        let nr_qbits = 5;
577        let nr_cbits = 2;
578        let state = LatexExportState::new(nr_qbits, nr_cbits);
579        assert_eq!(state.nr_qbits, nr_qbits);
580        assert_eq!(state.nr_cbits, nr_cbits);
581        assert_eq!(state.add_init, true);
582        assert_eq!(state.expand_composite, true);
583        assert_eq!(state.matrix, Vec::<Vec<Option<String>>>::new());
584        assert_eq!(state.in_use, vec![true; nr_qbits+nr_cbits]);
585        assert_eq!(state.controlled, false);
586        assert_eq!(state.loops, vec![]);
587        assert_eq!(state.open_loops, vec![]);
588    }
589
590    #[test]
591    fn test_total_nr_bits()
592    {
593        let state = LatexExportState::new(5, 2);
594        assert_eq!(state.total_nr_bits(), 7);
595
596        let state = LatexExportState::new(3, 0);
597        assert_eq!(state.total_nr_bits(), 3);
598
599        let state = LatexExportState::new(2, 8);
600        assert_eq!(state.total_nr_bits(), 10);
601    }
602
603    #[test]
604    fn test_add_column()
605    {
606        let mut state = LatexExportState::new(3, 1);
607        state.add_column();
608        assert_eq!(state.matrix, vec![vec![None, None, None, None]]);
609
610        state.matrix[0][1] = Some(String::from("x"));
611        state.add_column();
612        assert_eq!(state.matrix, vec![
613            vec![None, Some(String::from("x")), None, None],
614            vec![None, None, None, None]
615        ]);
616    }
617
618    #[test]
619    fn test_reserve()
620    {
621        let mut state = LatexExportState::new(2, 2);
622        assert_eq!(state.reserve(&[0], None), Ok(()));
623        assert_eq!(state.in_use, vec![false; 4]);
624        assert_eq!(state.matrix, vec![vec![None; 4]]);
625
626        state.in_use[0] = true;
627        assert_eq!(state.reserve(&[1], None), Ok(()));
628        assert_eq!(state.in_use, vec![true, false, false, false]);
629        assert_eq!(state.matrix, vec![vec![None, None, None, None]]);
630
631        assert_eq!(state.reserve(&[0], None), Ok(()));
632        assert_eq!(state.in_use, vec![false; 4]);
633        assert_eq!(state.matrix, vec![vec![None; 4]; 2]);
634
635        state.in_use[3] = true;
636        assert_eq!(state.reserve(&[0, 1], None), Ok(()));
637        assert_eq!(state.in_use, vec![false, false, false, true]);
638        assert_eq!(state.matrix, vec![vec![None; 4]; 2]);
639
640        assert_eq!(state.reserve(&[0, 1], Some(&[0])), Ok(()));
641        assert_eq!(state.in_use, vec![false, false, false, true]);
642        assert_eq!(state.matrix, vec![vec![None; 4]; 2]);
643
644        assert_eq!(state.reserve(&[0, 1], Some(&[1])), Ok(()));
645        assert_eq!(state.in_use, vec![false, false, false, false]);
646        assert_eq!(state.matrix, vec![vec![None; 4]; 3]);
647    }
648
649    #[test]
650    fn test_reserve_all()
651    {
652        let mut state = LatexExportState::new(2, 2);
653        state.reserve_all();
654        assert_eq!(state.in_use, vec![false; 4]);
655        assert_eq!(state.matrix, vec![vec![None; 4]]);
656
657        state.reserve_all();
658        assert_eq!(state.in_use, vec![false; 4]);
659        assert_eq!(state.matrix, vec![vec![None; 4]]);
660
661        state.in_use[0] = true;
662        state.reserve_all();
663        assert_eq!(state.in_use, vec![false; 4]);
664        assert_eq!(state.matrix, vec![vec![None; 4]; 2]);
665    }
666
667    #[test]
668    fn test_range_op()
669    {
670        let mut state = LatexExportState::new(2, 2);
671        assert_eq!(state.start_range_op(&[0], None), Ok(()));
672        assert_eq!(state.in_use, vec![false; 4]);
673        assert_eq!(state.matrix, vec![vec![None; 4]]);
674        state.end_range_op();
675        assert_eq!(state.in_use, vec![true, false, false, false]);
676        assert_eq!(state.matrix, vec![vec![None; 4]]);
677
678        assert_eq!(state.start_range_op(&[0, 1], None), Ok(()));
679        assert_eq!(state.in_use, vec![false; 4]);
680        assert_eq!(state.matrix, vec![vec![None; 4]; 2]);
681        state.end_range_op();
682        assert_eq!(state.in_use, vec![true, true, false, false]);
683        assert_eq!(state.matrix, vec![vec![None; 4]; 2]);
684
685        assert_eq!(state.start_range_op(&[0], None), Ok(()));
686        assert_eq!(state.in_use, vec![false; 4]);
687        assert_eq!(state.matrix, vec![vec![None; 4]; 3]);
688        state.end_range_op();
689        assert_eq!(state.in_use, vec![true, false, false, false]);
690        assert_eq!(state.matrix, vec![vec![None; 4]; 3]);
691
692        assert_eq!(state.start_range_op(&[1], None), Ok(()));
693        assert_eq!(state.in_use, vec![true, false, false, false]);
694        assert_eq!(state.matrix, vec![vec![None; 4]; 3]);
695        state.end_range_op();
696        assert_eq!(state.in_use, vec![true, true, false, false]);
697        assert_eq!(state.matrix, vec![vec![None; 4]; 3]);
698
699        assert_eq!(state.start_range_op(&[0], Some(&[1])), Ok(()));
700        assert_eq!(state.in_use, vec![false; 4]);
701        assert_eq!(state.matrix, vec![vec![None; 4]; 4]);
702        state.end_range_op();
703        assert_eq!(state.in_use, vec![true; 4]);
704        assert_eq!(state.matrix, vec![vec![None; 4]; 4]);
705    }
706
707    #[test]
708    fn test_set_field()
709    {
710        let mut state = LatexExportState::new(2, 0);
711        assert_eq!(state.set_field(0, String::from("hello")), Ok(()));
712        assert_eq!(state.in_use, vec![true, false]);
713        assert_eq!(state.matrix, vec![
714            vec![Some(String::from("hello")), None]
715        ]);
716
717        assert_eq!(state.set_field(1, String::from("world")), Ok(()));
718        assert_eq!(state.in_use, vec![true, true]);
719        assert_eq!(state.matrix, vec![
720            vec![Some(String::from("hello")), Some(String::from("world"))]
721        ]);
722
723        assert_eq!(state.set_field(0, String::from("hi there")), Ok(()));
724        assert_eq!(state.in_use, vec![true, false]);
725        assert_eq!(state.matrix, vec![
726            vec![Some(String::from("hello")), Some(String::from("world"))],
727            vec![Some(String::from("hi there")), None]
728        ]);
729
730        state.add_column();
731        assert_eq!(state.set_field(1, String::from("planet Mars")), Ok(()));
732        assert_eq!(state.in_use, vec![false, true]);
733        assert_eq!(state.matrix, vec![
734            vec![Some(String::from("hello")), Some(String::from("world"))],
735            vec![Some(String::from("hi there")), None],
736            vec![None, Some(String::from("planet Mars"))]
737        ]);
738    }
739
740    #[test]
741    fn test_set_measurement()
742    {
743        let mut state = LatexExportState::new(2, 2);
744        assert_eq!(state.set_measurement(0, 1, None), Ok(()));
745        assert_eq!(state.set_measurement(1, 0, Some("X")), Ok(()));
746        assert_eq!(state.code(),
747r#"\Qcircuit @C=1em @R=.7em {
748    \lstick{\ket{0}} & \meter & \qw & \qw \\
749    \lstick{\ket{0}} & \qw & \meterB{X} & \qw \\
750    \lstick{0} & \cw & \cw \cwx[-1] & \cw \\
751    \lstick{0} & \cw \cwx[-3] & \cw & \cw \\
752}
753"#);
754    }
755
756    #[test]
757    fn test_set_reset()
758    {
759        let mut state = LatexExportState::new(2, 0);
760        assert_eq!(state.set_reset(0), Ok(()));
761        assert_eq!(state.code(),
762r#"\Qcircuit @C=1em @R=.7em {
763    \lstick{\ket{0}} & \push{~\ket{0}~} \ar @{|-{}} [0,-1] & \qw \\
764    \lstick{\ket{0}} & \qw & \qw \\
765}
766"#);
767    }
768
769    #[test]
770    fn test_set_condition()
771    {
772        let mut state = LatexExportState::new(2, 2);
773        assert_eq!(state.start_range_op(&[], None), Ok(()));
774        assert_eq!(state.set_condition(&[0, 1], 2, &[]), Ok(()));
775        state.end_range_op();
776
777        assert_eq!(state.start_range_op(&[0], Some(&[0, 1])), Ok(()));
778        assert_eq!(state.set_field(0, String::from(r"\gate{X}")), Ok(()));
779        assert_eq!(state.set_condition(&[0, 1], 2, &[0]), Ok(()));
780        state.end_range_op();
781
782        assert_eq!(state.start_range_op(&[1], Some(&[0, 1])), Ok(()));
783        assert_eq!(state.set_field(1, String::from(r"\gate{H}")), Ok(()));
784        assert_eq!(state.set_condition(&[0, 1], 1, &[1]), Ok(()));
785        state.end_range_op();
786
787        assert_eq!(state.code(),
788r#"\Qcircuit @C=1em @R=.7em {
789    \lstick{\ket{0}} & \gate{X} & \qw & \qw \\
790    \lstick{\ket{0}} & \qw & \gate{H} & \qw \\
791    \lstick{0} & \cctrlo{-2} & \cctrl{-1} & \cw \\
792    \lstick{0} & \cctrl{-1} & \cctrlo{-1} & \cw \\
793}
794"#);
795    }
796
797    #[test]
798    fn test_add_block_gate()
799    {
800        let mut state = LatexExportState::new(1, 0);
801        assert_eq!(state.add_block_gate(&[0], "G"), Ok(()));
802        assert_eq!(state.code(),
803r#"\Qcircuit @C=1em @R=.7em {
804    \lstick{\ket{0}} & \gate{G} & \qw \\
805}
806"#);
807
808        let mut state = LatexExportState::new(3, 0);
809        assert_eq!(state.add_block_gate(&[1, 0, 2], "G"), Ok(()));
810        assert_eq!(state.code(),
811r#"\Qcircuit @C=1em @R=.7em {
812    \lstick{\ket{0}} & \multigate{2}{G} & \qw \\
813    \lstick{\ket{0}} & \ghost{G} & \qw \\
814    \lstick{\ket{0}} & \ghost{G} & \qw \\
815}
816"#);
817
818        let mut state = LatexExportState::new(5, 0);
819        assert_eq!(state.add_block_gate(&[1, 0, 3], "G"), Ok(()));
820        assert_eq!(state.code(),
821r#"\Qcircuit @C=1em @R=.7em {
822    \lstick{\ket{0}} & \multigate{1}{G} & \qw \\
823    \lstick{\ket{0}} & \ghost{G} & \qw \\
824    \lstick{\ket{0}} & \qw & \qw \\
825    \lstick{\ket{0}} & \gate{G} \qwx[-2] & \qw \\
826    \lstick{\ket{0}} & \qw & \qw \\
827}
828"#);
829    }
830
831    #[test]
832    fn test_loop()
833    {
834        let mut state = LatexExportState::new(2, 0);
835        state.start_loop(23);
836        assert_eq!(state.reserve(&[0, 1], None), Ok(()));
837        assert_eq!(state.set_field(0, String::from(r"\gate{H}")), Ok(()));
838        assert_eq!(state.set_field(1, String::from(r"\gate{X}")), Ok(()));
839        assert_eq!(state.add_cds(0, 1, r"\leftrightarrow"), Ok(()));
840        assert_eq!(state.reserve(&[0, 1], None), Ok(()));
841        assert_eq!(state.set_field(0, String::from(r"\gate{H}")), Ok(()));
842        assert_eq!(state.set_field(1, String::from(r"\gate{X}")), Ok(()));
843        assert_eq!(state.end_loop(), Ok(()));
844
845        assert_eq!(state.code(),
846r#"\Qcircuit @C=1em @R=.7em {
847    & \mbox{} \POS"2,2"."2,2"."2,4"."2,4"!C*+<.7em>\frm{^\}},+U*++!D{23\times}\\
848    & & & & \\
849    \lstick{\ket{0}} & \gate{H} & \cds{1}{\leftrightarrow} & \gate{H} & \qw \\
850    \lstick{\ket{0}} & \gate{X} & \qw & \gate{X} & \qw \\
851}
852"#);
853    }
854
855    #[test]
856    fn test_loop_close_error()
857    {
858        let mut state = LatexExportState::new(2, 0);
859        assert_eq!(state.end_loop(),
860            Err(crate::error::Error::ExportError(crate::error::ExportError::CantCloseLoop))
861        );
862    }
863
864    #[test]
865    fn test_set_barrier()
866    {
867        let mut state = LatexExportState::new(3, 0);
868        assert_eq!(state.set_field(0, String::from(r"\gate{X}")), Ok(()));
869        assert_eq!(state.set_field(1, String::from(r"\gate{X}")), Ok(()));
870        assert_eq!(state.set_field(2, String::from(r"\gate{X}")), Ok(()));
871        assert_eq!(state.set_barrier(&[0]), Ok(()));
872
873        assert_eq!(state.set_field(0, String::from(r"\gate{X}")), Ok(()));
874        assert_eq!(state.set_field(1, String::from(r"\gate{X}")), Ok(()));
875        assert_eq!(state.set_field(2, String::from(r"\gate{X}")), Ok(()));
876        assert_eq!(state.set_barrier(&[0, 2]), Ok(()));
877
878        assert_eq!(state.set_field(0, String::from(r"\gate{X}")), Ok(()));
879        assert_eq!(state.set_field(1, String::from(r"\gate{X}")), Ok(()));
880        assert_eq!(state.set_field(2, String::from(r"\gate{X}")), Ok(()));
881        assert_eq!(state.set_barrier(&[0, 1, 2]), Ok(()));
882
883        assert_eq!(state.code(),
884r#"\Qcircuit @C=1em @R=.7em {
885    \lstick{\ket{0}} & \gate{X} & \qw \barrier{0} & \gate{X} & \qw \barrier{0} & \gate{X} & \qw \barrier{2} & \qw \\
886    \lstick{\ket{0}} & \gate{X} & \qw & \gate{X} & \qw & \gate{X} & \qw & \qw \\
887    \lstick{\ket{0}} & \gate{X} & \qw & \gate{X} & \qw \barrier{0} & \gate{X} & \qw & \qw \\
888}
889"#);
890    }
891
892    #[test]
893    fn test_no_init()
894    {
895        let mut state = LatexExportState::new(1, 1);
896        assert_eq!(state.set_measurement(0, 0, None), Ok(()));
897
898        assert_eq!(state.code(),
899r#"\Qcircuit @C=1em @R=.7em {
900    \lstick{\ket{0}} & \meter & \qw \\
901    \lstick{0} & \cw \cwx[-1] & \cw \\
902}
903"#);
904
905        state.set_add_init(false);
906        assert_eq!(state.code(),
907r#"\Qcircuit @C=1em @R=.7em {
908     & \meter & \qw \\
909     & \cw \cwx[-1] & \cw \\
910}
911"#);
912    }
913
914    #[test]
915    fn test_default_trait_impl()
916    {
917        let gate = NoLatexGate {};
918        let mut state = LatexExportState::new(5, 0);
919        assert_eq!(gate.latex(&[1, 2, 4], &mut state), Ok(()));
920        assert_eq!(gate.latex(&[0, 2, 3], &mut state), Ok(()));
921        assert_eq!(state.code(),
922r#"\Qcircuit @C=1em @R=.7em {
923    \lstick{\ket{0}} & \qw & \gate{NLG} & \qw \\
924    \lstick{\ket{0}} & \multigate{1}{NLG} & \qw & \qw \\
925    \lstick{\ket{0}} & \ghost{NLG} & \multigate{1}{NLG} \qwx[-2] & \qw \\
926    \lstick{\ket{0}} & \qw & \ghost{NLG} & \qw \\
927    \lstick{\ket{0}} & \gate{NLG} \qwx[-2] & \qw & \qw \\
928}
929"#);
930    }
931}