Topology (entangling-layer patterns)¶
Every variational circuit (VQE, QAOA, hardware-efficient ansätze) needs an entangling
layer -- a set of two-qubit gates connecting qubits in some pattern -- and hand-writing
it as a for loop is one of the most repeated patterns in quantum-circuit code.
entangling_layer gives five of the standard patterns a name and a single call
instead, the same role Qiskit's TwoLocal(entanglement=...) or PennyLane's
qml.broadcast(pattern=...) play.
Step 1. The five patterns, on 4 qubits¶
from dense_evolution.circuits.topology import entangling_layer
for pattern in ('linear', 'circular', 'full', 'star', 'brick'):
print(pattern, entangling_layer(4, pattern=pattern))
linear [('cx', 0, 1), ('cx', 1, 2), ('cx', 2, 3)]
circular [('cx', 0, 1), ('cx', 1, 2), ('cx', 2, 3), ('cx', 3, 0)]
full [('cx', 0, 1), ('cx', 0, 2), ('cx', 0, 3), ('cx', 1, 2), ('cx', 1, 3), ('cx', 2, 3)]
star [('cx', 0, 1), ('cx', 0, 2), ('cx', 0, 3)]
brick [('cx', 0, 1), ('cx', 2, 3), ('cx', 1, 2)]
Each call returns a plain gate-tuple list, ready for run_circuit like any hand-built
circuit. linear is a chain, circular adds one wraparound edge closing it into a
ring, full connects every pair (the most expressive, and the most gates), star
routes everything through one hub qubit, and brick alternates even/odd pairs into
the staircase pattern behind most Trotterized and hardware-efficient ansätze.

The diagram above is the real brick pattern from Step 1, drawn with
de.plot_circuit(entangling_layer(4, pattern='brick'), 4) -- (0,1) and (2,3) fire
in the same layer, then (1,2) bridges them in the next.
Step 2. Use one as an ansatz layer¶
import numpy as np
import dense_evolution as de
from dense_evolution.circuits.topology import entangling_layer
sim = de.DenseSVSimulator(4)
ops = [('h', i) for i in range(4)] + entangling_layer(4, pattern='brick')
sim.run_circuit(ops)
print(round(float(np.sum(sim.get_probabilities())), 6))
entangling_layer's output concatenates directly onto any other gate list -- here, a
layer of H on every qubit (the usual first layer of a hardware-efficient ansatz)
followed by one brick entangling layer. The probabilities still sum to 1, the same
sanity check worth running on any new ansatz layer before trusting energies computed
from it in a real VQE loop.
Details¶
gate parameter: any two-qubit gate name works ('cx', 'cz', 'cy', or a
custom name registered elsewhere) -- it's not validated against
dense_evolution.gates.GATES here, so an unregistered name only fails later, at
run_circuit time.
reverse=True swaps (control, target) to (target, control) on every edge in
the pattern -- some ansätze alternate direction layer to layer for symmetry.
hub parameter only affects pattern='star': it picks which qubit every other
qubit connects to (default 0).
This package's DenseSVSimulator has no notion of hardware connectivity at all --
any two qubits can always interact directly, regardless of index distance. These five
patterns are an ansatz-design convenience (fewer parameters, known symmetry), not a
constraint the simulator enforces the way a real superconducting chip's physical
layout would.
See also: States -- ghz_state builds its cx chain with
entangling_layer(pattern='linear') directly, the simplest possible use of this
module.
topology ¶
Entangling-layer topology helpers.
Every variational circuit (VQE, QAOA, hardware-efficient ansätze) needs an
entangling layer, and hand-writing it as a for loop of two-qubit gates is
one of the most repeated patterns across quantum-circuit code. Other
libraries give it a name and a single call instead (Qiskit's
TwoLocal(entanglement=...), PennyLane's qml.broadcast(pattern=...)).
entangling_layer is the Dense-Evolution equivalent: it returns a plain
list of gate tuples in the circuit format run_circuit already accepts, so
it drops straight into any existing circuit list via concatenation.
entangling_layer ¶
Build a list of two-qubit gate tuples connecting n_qubits according to a named topology.
Patterns
'linear' -- chain: (0,1), (1,2), ..., (n-2,n-1) 'circular' -- linear + one wraparound edge (n-1,0) ("ring"); identical to 'linear' when n_qubits == 2, since there is only one possible edge between two qubits 'full' -- every pair (i,j) with i<j ("complete"/all-to-all) 'star' -- a single hub qubit connected to every other qubit 'brick' -- alternating even/odd layers: (0,1)(2,3).. then (1,2)(3,4).. ("brickwork"/staircase, the pattern behind most Trotterized and hardware-efficient ansätze)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
Number of qubits involved, must be >= 2. |
required |
pattern
|
str
|
One of VALID_PATTERNS. |
'linear'
|
gate
|
str
|
Two-qubit gate name applied to every edge (e.g. 'cx', 'cz', 'cy'). Not validated against dense_evolution.gates.GATES here, so a custom gate name registered elsewhere still works. |
'cx'
|
reverse
|
bool
|
Swap (control, target) -> (target, control) for every edge. Some ansätze alternate direction layer to layer for symmetry. |
False
|
hub
|
int
|
Hub qubit index, only used by pattern='star'. |
0
|
Returns:
| Type | Description |
|---|---|
list[tuple[str, int, int]]
|
|