## Circuits and Qubits

Let’s take a look at the core abstractions that, for the most part, serve as immutable containers for various quantum primitives. The top-level primitive is called `Circuit`

. Each circuit can be thought of as a container for one `QubitRegister`

—a group of qubits (`Qubit`

)—and a sequence of quantum operations (`Op`

).

Circuits can be combined sequentially:

```
val newCircuit = Circuit(H(0)).combine(Circuit(CNOT(0, 1))
```

All circuits come with an implicit qubit register where all qubits are initialized at $\lvert0\rangle$. The number of qubits is based on the highest operation index. For example, `Circuit(H(5))`

will be initialized with a register of six qubits (index starts at zero). You can always specify a custom register by applying `withRegister`

to your circuit:

```
Circuit(CNOT(0, 2)).withRegister(Qubit.one, Qubit.zero, Qubit.zero)
```

Qubits are immutable containers with two `Complex`

numbers describing their quantum state:

$\alpha$ and $\beta$ match `Qubit`

`a`

and `b`

parameters. Since these parameters represent qubit probabilities their squares have to add up to one:

All qubits in the register have to be accessed by their index in the underlying sequence. For easy access to the actual numerical indexes `Circuit`

has a helper property `indexes`

.

Qubits implement the `Labeled`

trait, which means that you can apply a unique string label to any qubit:

```
val testQubit = Qubit.one("test")
val messageQubit = Qubit(Complex(0.8), Complex(0.6), "message")
```

Labels are useful for when you need to quickly differentiate between qubits and when you look at the final classical register readouts after the measurement.