Skip to content

Commit 5da6a54

Browse files
ianyfanThomas HoffmannDimitri KartsaklisnikhilkhatriCharles London
committed
Release version 0.3.3
Co-authored-by: Thomas Hoffmann <thomas.hoffmann@quantinuum.com> Co-authored-by: Dimitri Kartsaklis <dimitri.kartsaklis@quantinuum.com> Co-authored-by: Nikhil Khatri <nikhil.khatri@quantinuum.com> Co-authored-by: Charles London <charles.london@quantinuum.com>
1 parent c4d67fd commit 5da6a54

24 files changed

+496
-336
lines changed

docs/examples/classical_pipeline.ipynb

+14-13
Large diffs are not rendered by default.

docs/examples/quantum_pipeline.ipynb

+17-17
Large diffs are not rendered by default.

docs/examples/quantum_pipeline_jax.ipynb

+19-19
Large diffs are not rendered by default.

docs/examples/rotosolve_optimizer.ipynb

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"cell_type": "markdown",
55
"metadata": {},
66
"source": [
7-
"# Rotosolve Optimizer"
7+
"# Rotosolve optimizer"
88
]
99
},
1010
{
@@ -195,7 +195,7 @@
195195
"\n",
196196
" initial_loss = loss(trainer.model([train_circuit]), None)\n",
197197
"\n",
198-
" trainer.fit(train_dataset, logging_step=12)\n",
198+
" trainer.fit(train_dataset, log_interval=12)\n",
199199
" losses.append([initial_loss] + trainer.train_epoch_costs)"
200200
]
201201
},
@@ -253,7 +253,7 @@
253253
"cell_type": "markdown",
254254
"metadata": {},
255255
"source": [
256-
"## Final Output"
256+
"## Final output"
257257
]
258258
},
259259
{

docs/package-api.rst

+5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ Concrete implementations of classical and quantum :term:`ansätze <ansatz (plura
1818
.. inheritance-diagram::
1919
lambeq.ansatz.IQPAnsatz
2020
lambeq.ansatz.MPSAnsatz
21+
lambeq.ansatz.Sim14Ansatz
22+
lambeq.ansatz.Sim15Ansatz
2123
lambeq.ansatz.SpiderAnsatz
24+
lambeq.ansatz.StronglyEntanglingAnsatz
2225
lambeq.ansatz.Symbol
2326
:top-classes: lambeq.ansatz.base.Symbol
2427
:parts: 1
@@ -172,9 +175,11 @@ Provides a selection of :term:`trainers <trainer>`, :term:`models <model>`, and
172175
lambeq.training.Dataset
173176
lambeq.training.MSELoss
174177
lambeq.training.LossFunction
178+
lambeq.training.NelderMeadOptimizer
175179
lambeq.training.NumpyModel
176180
lambeq.training.PytorchModel
177181
lambeq.training.PytorchTrainer
182+
lambeq.training.RotosolveOptimizer
178183
lambeq.training.SPSAOptimizer
179184
lambeq.training.TketModel
180185
lambeq.training.PennyLaneModel

docs/puml/ansatz.puml

+15-7
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ class TensorAnsatz {
1717
functor
1818
}
1919
class CircuitAnsatz {
20-
functor
20+
functor: Functor
2121
ob_map: Mapping[Ty, int]
22+
n_layers: int
23+
n_single_qubit_params: int
24+
discard: bool
2225
}
2326
class MPSAnsatz {
2427
BOND_TYPE
@@ -32,12 +35,12 @@ class SpiderAnsatz {
3235
split_functor
3336
tensor_functor
3437
}
35-
class IQPAnsatz {
36-
discard: bool
37-
functor
38-
n_layers: int
39-
n_single_qubit_params: int
40-
}
38+
39+
class IQPAnsatz {}
40+
class StronglyEntanglingAnsatz {}
41+
class Sim14Ansatz {}
42+
class Sim15Ansatz {}
43+
4144
class Symbol {
4245
size: int
4346
sort_key(order)
@@ -58,6 +61,9 @@ BaseAnsatz <|-- CircuitAnsatz
5861
TensorAnsatz <|-- MPSAnsatz
5962
TensorAnsatz <|-- SpiderAnsatz
6063
CircuitAnsatz <|-- IQPAnsatz
64+
CircuitAnsatz <|-- StronglyEntanglingAnsatz
65+
CircuitAnsatz <|-- Sim14Ansatz
66+
CircuitAnsatz <|-- Sim15Ansatz
6167
discopy.monoidal.Ty <|-- discopy.rigid.Ty
6268

6369
MPSAnsatz::split_functor *-left- discopy.rigid.Functor
@@ -70,4 +76,6 @@ TensorAnsatz::functor *-- discopy.quantum.circuit.Functor
7076
IQPAnsatz::functor *-- discopy.quantum.circuit.Functor
7177
sympy.core.symbol.Symbol <|-- Symbol
7278

79+
BaseAnsatz --> Symbol : uses
80+
7381
@enduml

docs/puml/img/ansatz.png

23.6 KB
Loading

docs/puml/img/training.png

9.69 KB
Loading

docs/puml/training.puml

+11-9
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ abstract class Trainer {
3535

3636
abstract class Optimizer {
3737
model
38+
loss
39+
hyperparams: dict[str, float]
40+
bounds
3841
{abstract} backward()
3942
{abstract} step()
4043
{abstract} state_dict()
@@ -76,15 +79,11 @@ class PytorchTrainer {
7679
optimizer
7780
}
7881

79-
class SPSAOptimizer {
80-
hyperparams
81-
loss_fn
82-
bounds
83-
}
82+
class SPSAOptimizer {}
83+
class NelderMeadOptimizer {}
84+
class RotosolveOptimizer {}
8485

85-
class BinaryCrossEntropyLoss {
86-
calculate_loss()
87-
}
86+
class BinaryCrossEntropyLoss {}
8887

8988
class CrossEntropyLoss {
9089
calculate_loss()
@@ -108,6 +107,8 @@ Trainer <|-- PytorchTrainer
108107
Trainer <|-- QuantumTrainer
109108

110109
Optimizer <|-- SPSAOptimizer
110+
Optimizer <|-- NelderMeadOptimizer
111+
Optimizer <|-- RotosolveOptimizer
111112

112113
PennyLaneModel -- pennylane
113114
PennyLaneModel -- pytorch
@@ -120,8 +121,9 @@ Trainer *-- CheckPoint
120121
CheckPoint --* Model
121122
Trainer::model *- Model
122123
Trainer *-u- Dataset
123-
Model -* Optimizer::model
124+
QuantumModel -* Optimizer::model
124125
Optimizer -* QuantumTrainer::optimizer
126+
LossFunction --* Optimizer::loss
125127

126128
PennyLaneModel -- PytorchTrainer: usedWith
127129
PytorchModel -- PytorchTrainer: usedWith

docs/release_notes.rst

+24
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,30 @@
33
Release notes
44
=============
55

6+
.. _rel-0.3.3:
7+
8+
`0.3.3 <https://github.com/CQCL/lambeq/releases/tag/0.3.3>`_
9+
------------------------------------------------------------
10+
This update features contributions from participants in `unitaryHACK 2023 <https://unitaryhack.dev/>`_:
11+
12+
- Two new optimisers:
13+
- The Nelder-Mead optimiser. (credit: `Gopal Dahale <https://github.com/CQCL/lambeq/pull/104>`_)
14+
- The Rotosolve optimiser. (credit: `Ahmed Darwish <https://github.com/CQCL/lambeq/pull/93>`_)
15+
- A new rewrite rule for handling unknown words. (credit: `WingCode <https://github.com/CQCL/lambeq/pull/105>`_)
16+
17+
Many thanks to all who participated.
18+
19+
This update also contains the following changes:
20+
21+
Added:
22+
23+
- :py:class:`~lambeq.DiagramRewriter` is a new class that rewrites diagrams by looking at the diagram as a whole rather than by using rewrite rules on individual boxes. This includes an example :py:class:`~lambeq.UnifyCodomainRewriter` which adds an extra box to the end of diagrams to change the output to a specified type. (credit: `A.C.E07 <https://github.com/CQCL/lambeq/pull/111>`_)
24+
- Added an early stopping mechanism to :py:class:`~lambeq.Trainer` using the parameter ``early_stopping_interval``.
25+
26+
Fixed:
27+
28+
- In :py:class:`~lambeq.PennyLaneModel`, SymPy symbols are now substituted during the forward pass so that gradients are back-propagated to the original parameters.
29+
- A pickling error that prevented CCG trees produced by :py:class:`~lambeq.BobcatParser` from being unpickled has been fixed.
630

731
.. _rel-0.3.2:
832

docs/tutorials/trainer_classical.ipynb

+30-28
Large diffs are not rendered by default.

docs/tutorials/trainer_hybrid.ipynb

+47-37
Large diffs are not rendered by default.

docs/tutorials/trainer_quantum.ipynb

+39-26
Large diffs are not rendered by default.

lambeq/bobcat/fast_int_enum.py

+3
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ def __init_subclass__(cls) -> None:
8484
def __new__(cls, value: str) -> FastIntEnum:
8585
return cls._member_map_[value]
8686

87+
def __getnewargs__(self) -> tuple[str]: # type: ignore[override]
88+
return (str(self),)
89+
8790
def __repr__(self) -> str:
8891
return f'{self.__class__.__name__}.{self.names[self]}'
8992

lambeq/training/nelder_mead_optimizer.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ def __init__(self,
8787
- `fatol`: float, default: 1e-4
8888
The acceptable level of absolute error in the loss value
8989
between iterations that indicates convergence.
90-
}
9190
9291
Parameters
9392
----------
@@ -104,22 +103,21 @@ def __init__(self,
104103
------
105104
ValueError
106105
- If the hyperparameters are not set correctly, or if the
107-
length of `bounds` does not match the number of the model
108-
parameters.
106+
length of `bounds` does not match the number of the model
107+
parameters.
109108
- If the lower bounds are greater than the upper bounds.
110109
- If the initial simplex is not a 2D array.
111110
- If the initial simplex does not have N+1 rows, where N is
112-
the number of model parameters.
111+
the number of model parameters.
113112
114-
Warnings
115-
--------
113+
Warning
116114
- If the initial model weights are not within the bounds.
117115
118116
References
119117
----------
120118
Gao, Fuchang & Han, Lixing. (2012). Implementing the Nelder-Mead
121-
simplex algorithm with adaptive parameters.
122-
Computational Optimization and Applications. 51. 259-277.
119+
Simplex Algorithm with Adaptive Parameters.
120+
`Computational Optimization and Applications`, 51. 259-277.
123121
10.1007/s10589-010-9329-3.
124122
125123
"""

lambeq/training/pennylane_model.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ def __init__(self,
6969
Model.__init__(self)
7070
torch.nn.Module.__init__(self)
7171
self.circuit_map: dict[Circuit, PennyLaneCircuit] = {}
72+
self.symbol_weight_map: dict[Symbol, torch.FloatTensor] = {}
7273
self._probabilities = probabilities
7374
self._normalize = normalize
7475
self._diff_method = diff_method
@@ -93,6 +94,7 @@ def _load_checkpoint(self, checkpoint: Checkpoint) -> None:
9394
self._backend_config = checkpoint['model_backend_config']
9495
self.circuit_map = checkpoint['model_circuits']
9596
self.load_state_dict(checkpoint['model_state_dict'])
97+
self.symbol_weight_map = dict(zip(self.symbols, self.weights))
9698

9799
for p_circ in self.circuit_map.values():
98100
p_circ.initialise_device_and_circuit()
@@ -150,10 +152,8 @@ def initialise_weights(self) -> None:
150152
[torch.nn.Parameter(torch.rand(1).squeeze())
151153
for _ in self.symbols]
152154
)
153-
symbol_weight_map = dict(zip(self.symbols, self.weights))
154155

155-
for p_circ in self.circuit_map.values():
156-
p_circ.initialise_concrete_params(symbol_weight_map)
156+
self.symbol_weight_map = dict(zip(self.symbols, self.weights))
157157

158158
def get_diagram_output(self, diagrams: list[Diagram]) -> torch.Tensor:
159159
"""Evaluate outputs of circuits using PennyLane.
@@ -175,8 +175,12 @@ def get_diagram_output(self, diagrams: list[Diagram]) -> torch.Tensor:
175175
Resulting tensor.
176176
177177
"""
178-
circuit_evals = [self.circuit_map[d].eval()
179-
for d in diagrams]
178+
circuit_evals = []
179+
for d in diagrams:
180+
p_circ = self.circuit_map[d]
181+
p_circ.initialise_concrete_params(self.symbol_weight_map)
182+
circuit_evals.append(p_circ.eval())
183+
180184
if self._normalize:
181185
if self._probabilities:
182186
circuit_evals = [c / torch.sum(c) for c in circuit_evals]

lambeq/training/quantum_trainer.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,16 @@ def validation_step(
191191
def fit(self,
192192
train_dataset: Dataset,
193193
val_dataset: Dataset | None = None,
194-
evaluation_step: int = 1,
195-
logging_step: int = 1) -> None:
194+
log_interval: int = 1,
195+
eval_interval: int = 1,
196+
early_stopping_interval: int | None = None) -> None:
196197

197198
self.model._training = True
198199

199-
super().fit(train_dataset, val_dataset, evaluation_step, logging_step)
200+
super().fit(train_dataset,
201+
val_dataset,
202+
log_interval,
203+
eval_interval,
204+
early_stopping_interval)
200205

201206
self.model._training = False

lambeq/training/rotosolve_optimizer.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232

3333
class RotosolveOptimizer(Optimizer):
34-
"""An Optimizer using the Rotosolve algorithm.
34+
"""An optimizer using the Rotosolve algorithm.
3535
3636
Rotosolve is an optimizer for parametrized quantum circuits. It
3737
applies a shift of ±π/2 radians to each parameter, then updates the
@@ -41,7 +41,7 @@ class RotosolveOptimizer(Optimizer):
4141
This optimizer is designed to work with ansätze that are composed of
4242
single-qubit rotations, such as the
4343
:py:class:`.StronglyEntanglingAnsatz`, :py:class:`.Sim14Ansatz`
44-
and :py:class:`.Sim14Ansatz`.
44+
and :py:class:`.Sim15Ansatz`.
4545
4646
See `Ostaszewski et al.
4747
<https://quantum-journal.org/papers/q-2021-01-28-391/pdf/>`_ for

0 commit comments

Comments
 (0)