# Construct circuits

This page takes a closer look at the `QuantumCircuit`

class in the Qiskit SDK, including some more advanced methods you can use to create quantum circuits.

## What is a quantum circuit?

A simple quantum circuit is a collection of qubits and a list of instructions that act on those qubits. To demonstrate, the following cell creates a new circuit with two new qubits, then displays the circuit's `qubits`

attribute.

```
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.qubits
```

Output:

```
[Qubit(QuantumRegister(2, 'q'), 0), Qubit(QuantumRegister(2, 'q'), 1)]
```

Adding an instruction to the circuit appends the instruction to the circuit's `data`

attribute. The following cell output shows `data`

is a list of `CircuitInstruction`

objects, each of which has an `operation`

attribute, and a `qubits`

attribute.

```
qc.x(0) # Add X-gate to qubit 0
qc.data
```

Output:

```
[CircuitInstruction(operation=Instruction(name='x', num_qubits=1, num_clbits=0, params=[]), qubits=(Qubit(QuantumRegister(2, 'q'), 0),), clbits=())]
```

The easiest way to view this information is through the `draw`

method, which returns a visualization of a circuit. See Visualize circuits for different ways of displaying quantum circuits.

`qc.draw("mpl")`

Output:

Circuit instruction objects can contain "definition" circuits that describe the instruction in terms of more fundamental instructions. For example, the X-gate is defined as a specific case of the U3-gate, a more general single-qubit gate.

[4] :```
# Draw definition circuit of 0th instruction in `qc`
qc.data[0].operation.definition.draw("mpl")
```

Output:

Instructions and circuits are similar in that they both describe operations on bits and qubits, but they have different purposes:

- Instructions are treated as fixed, and their methods will usually return new instructions (without mutating the original object).
- Circuits are designed to be built over many lines of code, and
`QuantumCircuit`

methods often mutate the existing object.

The rest of this page illustrates how to manipulate quantum circuits.

## Build circuits

Methods such as `QuantumCircuit.h`

and `QuantumCircuit.cx`

add specific instructions to circuits. To add instructions to a circuit more generally, use the `append`

method. This takes an instruction and a list of qubits to apply the instruction to. See the Circuit Library API documentation for a list of supported instructions.

```
from qiskit.circuit.library import HGate
qc = QuantumCircuit(1)
qc.append(
HGate(), # New HGate instruction
[0] # Apply to qubit 0
)
qc.draw("mpl")
```

Output:

To combine two circuits, use the `compose`

method. This accepts another `QuantumCircuit`

and an optional list of qubit mappings.

```
qc_a = QuantumCircuit(4)
qc_a.x(0)
qc_b = QuantumCircuit(2, name="qc_b")
qc_b.y(0)
qc_b.z(1)
# compose qubits (0, 1) of qc_a to qubits (1, 3) of qc_b respectively
combined = qc_a.compose(qc_b, qubits=[1, 3])
combined.draw("mpl")
```

Output:

You might also want to compile circuits into instructions to keep your circuits organized. You can convert a circuit to an instruction by using the `to_instruction`

method, then append this to another circuit as you would any other instruction. The circuit drawn in the following cell is functionally equivalent to the circuit drawn in the previous cell.

```
inst = qc_b.to_instruction()
qc_a.append(inst, [1, 3])
qc_a.draw("mpl")
```

Output:

If your circuit is unitary, you can convert it to a `Gate`

by using the `to_gate`

method. `Gate`

objects are specific types of instructions that have some extra features, such as the `control`

method, which adds a quantum control.

```
gate = qc_b.to_gate().control()
qc_a.append(gate, [0, 1, 3])
qc_a.draw("mpl")
```

Output:

To see what's going on, you can use the `decompose`

method to expand each instruction into its definition.

The `decompose`

method returns a new circuit and does **not** mutate the circuit it acts on.

`qc_a.decompose().draw("mpl")`

Output:

## Parameterized circuits

Many near-term quantum algorithms involve executing many variations of a quantum circuit. Since constructing and optimizing large circuits can be computationally expensive, Qiskit supports **parameterized** circuits. These circuits have undefined parameters, and their values do not need to be defined until just before executing the circuit. This lets you move circuit construction and optimization out of the main program loop. The following cell creates and displays a parameterized circuit.

```
from qiskit.circuit import Parameter
angle = Parameter("angle") # undefined number
# Create and optimize circuit once
qc = QuantumCircuit(1)
qc.rx(angle, 0)
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
qc = generate_preset_pass_manager(optimization_level=3, basis_gates=['u', 'cx']).run(qc)
qc.draw("mpl")
```

Output:

The following cell creates many variations of this circuit and displays one of the variations.

[11] :```
circuits = []
for value in range(100):
circuits.append(
qc.assign_parameters({ angle: value })
)
circuits[0].draw("mpl")
```

Output:

You can find a list of a circuit's undefined parameters in its `parameters`

attribute.

`qc.parameters`

Output:

```
ParameterView([Parameter(angle)])
```

## Next steps

- To learn about near-term quantum algorithms, take our Variational algorithm design course.
- See an example of circuits being used in the Grover's Algorithm tutorial.
- Work with simple circuits in the Explore gates and circuits with the Quantum Composer tutorial.