Git Product home page Git Product logo

Comments (6)

Gistbatch avatar Gistbatch commented on July 23, 2024 1

I think 2 is better unless there are other ways to specify qubits we must take care of. Potentially, we can also relax this to be rectangular instead.

from tqec.

Gistbatch avatar Gistbatch commented on July 23, 2024

Do you already have a solution in mind?
For me, these are two separate issues:

1 How to implement the temporal dimension

We should first target the base building blocks we currently express with SketchUp.
I'm in favor of a simple solution; a 3d grid structure is probably not necessary

  • Extend the plaquette/template library to cover all the necessary pieces
  • Add a linear scaling parameter for the main component
    • Add circuit generation accordingly
    • For observables, the notion of midline has to be extended to the temporal axis
    • We need to handle a start time

We need a concept similar to ComposedTemplate for the temporal direction, giving an order to temporal blocks and how they connect.
One possible solution could be introducing a concept of Computation representing a fixed order of operations.

2 How to switch between spatial and temporal views

I don't know a good way of thinking about this.
For me, the simplest solution would probably be to think of this as a relabeling of axes.
With that, by default, every template would be in spatial view; changing temporal boundaries would be executed by relabel_axes -> replace_spatial_boundarie -> relabel_axes. For this to work, the relabeling has to be very general.

from tqec.

nelimee avatar nelimee commented on July 23, 2024

I do not have a definite idea in mind, but I have some tracks.

For example, I like the idea of separating "cubes" into logical code units that would contain an initial layer, a repeated layer, and a final layer. This could very much be represented as

@dataclass
class ComputationLayer:
    template: Template
    plaquettes: list[Plaquette]

@dataclass
class ComputationBlock:
    start: ComputationLayer
    repeated: ComputationLayer
    repeat_count: int
    final: ComputationLayer

or if we restrict a "block" to be defined on the same template (which seems reasonable for my current view of what we want to do):

@dataclass
class ComputationBlock:
    template: Template
    start_plaquettes: list[Plaquette]
    repeated_plaquettes: list[Plaquette]
    repeat_count: int
    final_plaquettes: list[Plaquette]

These blocks could then be linked in whatever direction using a graph-like approach like in ComposedTemplate internal implementation.

Also, the more I think about it the more I feel like we need (at least for the moment) to drop the generality over time/space dimensions. Basically, say that there is only one direction that represent time and make it "hard-coded". This should not really limit expressibility, as users would still be able to relabel the axes before using the tqec library (basically rotating the 3-dimensional SketchUp computation before sending it to tqec), and would greatly reduce the complexity of our implementation.

So basically, I think we should only consider what you present in section 1, leaving section 2 to other tools or the user.

from tqec.

Gistbatch avatar Gistbatch commented on July 23, 2024

This looks very similar to what I had in mind.
I'm unaware of any cases where we need to change the template during one block.
Maybe this is necessary for certain operations @afowler?

from tqec.

afowler avatar afowler commented on July 23, 2024

from tqec.

nelimee avatar nelimee commented on July 23, 2024

So I thought a little bit on this issue yesterday, and here is my current state of mind.

We want to be able to represent different kind of "blocks". The first 2 we have at the moment are "repeating blocks" containing an initial layer, a repeated layer, and a final layer, and "state injection" blocks. This calls for a common interface for a "block", that will then be implemented differently depending on the block.

For me, any kind of block should have:

  1. a way to query the 3-dimensional (2 spatial dimensions and 1 temporal dimension) space they need. The first step will be to simply be able to represent 3-dimensional volumes with edges (sides of the structure) that are parallel to the axes, in which case the "space they need" can simply be represented as a 3-dimensional point. Then, we might need to lift that assumption, e.g., for the shifting memory that moves the logical qubit one qubit away from where it was at the previous round, and be able to represent 3-dimensional structures with edges that might not be parallel to the time dimension.
  2. a way to return the quantum circuit they represent.

I have made a quick experiment with that in mind and that gave:

from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass

import cirq
import cirq.circuits

from tqec.circuit.circuit import generate_circuit
from tqec.circuit.schedule import ScheduledCircuit, merge_scheduled_circuits
from tqec.exceptions import TQECException
from tqec.plaquette.plaquette import Plaquette
from tqec.templates.base import Template


@dataclass
class Position3D:
    x: int
    y: int
    z: int


@dataclass
class ComputationBlock(ABC):
    @property
    @abstractmethod
    def needed_time(self) -> int:
        pass

    @abstractmethod
    def instantiate(self) -> cirq.Circuit:
        pass


def _number_of_moments_needed(plaquettes: list[Plaquette]) -> int:
    return max(max(p.circuit.schedule) for p in plaquettes)


@dataclass
class StandardComputationBlock(ComputationBlock):
    template: Template
    initial_plaquettes: list[Plaquette]
    final_plaquettes: list[Plaquette]
    repeating_plaquettes: tuple[list[Plaquette], int] | None

    def __post_init__(self):
        expected_plaquette_number = self.template.expected_plaquettes_number
        if len(self.initial_plaquettes) != expected_plaquette_number:
            raise TQECException(
                f"Could not instantiate a ComputationBlock with {len(self.initial_plaquettes)} "
                f"initial plaquettes and a template that requires {expected_plaquette_number} "
                "plaquettes."
            )
        if len(self.final_plaquettes) != expected_plaquette_number:
            raise TQECException(
                f"Could not instantiate a ComputationBlock with {len(self.final_plaquettes)} "
                f"final plaquettes and a template that requires {expected_plaquette_number} "
                "plaquettes."
            )
        if (
            self.repeating_plaquettes is not None
            and len(self.repeating_plaquettes[0]) != expected_plaquette_number
        ):
            raise TQECException(
                f"Could not instantiate a ComputationBlock with {len(self.repeating_plaquettes)} "
                f"repeating plaquettes and a template that requires {expected_plaquette_number} "
                "plaquettes."
            )

    @property
    def is_connector(self) -> bool:
        return self.repeating_plaquettes is None

    @property
    def needed_time(self) -> int:
        time = _number_of_moments_needed(self.initial_plaquettes)
        if self.repeating_plaquettes is not None:
            plaquettes, repetitions = self.repeating_plaquettes
            time += repetitions * _number_of_moments_needed(plaquettes)
        time += _number_of_moments_needed(self.final_plaquettes)
        return time

    def instantiate(self) -> cirq.Circuit:
        circuit = generate_circuit(self.template, self.initial_plaquettes)
        if self.repeating_plaquettes is not None:
            plaquettes, repetitions = self.repeating_plaquettes
            inner_circuit = generate_circuit(self.template, plaquettes).freeze()
            circuit += cirq.CircuitOperation(inner_circuit, repetitions=repetitions)
        circuit += generate_circuit(self.template, self.final_plaquettes)
        return circuit


@dataclass
class Computation:
    blocks: list[ComputationBlock]
    positions: list[Position3D]

    def to_circuit(self) -> cirq.Circuit:
        time_positions = [position.z for position in self.positions]
        shifted_circuits = [
            block.instantiate().transform_qubits(lambda q: q + (position.x, position.y))
            for block, position in zip(self.blocks, self.positions)
        ]
        instantiated_scheduled_blocks = [
            ScheduledCircuit(circuit, starting_time)
            for circuit, starting_time in zip(shifted_circuits, time_positions)
        ]
        return merge_scheduled_circuits(instantiated_scheduled_blocks)

(with a small modification to ScheduledCircuit that includes the possibility to give an integer, in which case moments are scheduled from that integer value as list(range(start, start + number_of_moments_in_circuit)))

The above code is simply a first exploration, but will already require some changes in the Template hierarchy. Basically, we should have a way to query the spatial boundaries of a specific kind of Template and to change the plaquettes applied on these specific regions.
For that purpose, we discard from the list of templates to support anything that is not in the shape of a logical qubit, because generically defining what is "on the boundary" and what is not is hard (not impossible with ComposedTemplate, but nevertheless hard) and will require the composed templates to include a distance-1 (in the sense "one plaquette on the interesting dimension) template on each boundary.
For the basic building block of qubit, we currently have two classes:

  • The DenseQubitSquareTemplate
    1  5  6  5  6  2
    7  9 10  9 10 11
    8 10  9 10  9 12
    7  9 10  9 10 11
    8 10  9 10  9 12
    3 13 14 13 14  4
    
    that is the most generic representation of a scalable logical qubit,
  • The QubitSquareTemplate
    .  .  1  .  1  .
    2  3  4  3  4  .
    .  4  3  4  3  5
    2  3  4  3  4  .
    .  4  3  4  3  5
    .  6  .  6  .  .
    
    that enforces the standard parity placement on weight-2 stabilizers.

The DenseQubitSquareTemplate will be the most (only) used template, as QubitSquareTemplate does not allow any plaquette on corners, and this is required for all the operations we might be interested in (e.g., merging/splitting).

So I can see 2 ways forward:

  1. Keep both classes, define an abstract SurroundedSquareTemplate that will provide ways to query/replace templates/plaquettes on a specific boundary of the template, and re-implement both DenseQubitSquareTemplate and QubitSquareTemplate using that base class.
  2. Remove completely QubitSquareTemplate, implement a way to query/replace templates/plaquettes on a specific boundary of a DenseQubitSquareTemplate instance.

Any opinion on that?

from tqec.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.