Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
246 commits
Select commit Hold shift + click to select a range
a9b2115
Added folder Noise_characterization
MaxFroehlich1410 Feb 19, 2025
e4c5def
added optimization folder
MaxFroehlich1410 Feb 19, 2025
9698629
added optimization.py
MaxFroehlich1410 Feb 20, 2025
15b5530
moved noise_char directory. updated loss_function
aleramos119 Feb 20, 2025
329841c
BFGS implemented
aleramos119 Feb 20, 2025
2a41de5
BFGS bug fixed
aleramos119 Feb 20, 2025
96896fd
updated BFGS
aleramos119 Feb 25, 2025
6e71232
updated BFGS
aleramos119 Feb 25, 2025
f994a10
Merge remote-tracking branch 'origin/Noise_Characterization' into Noi…
aleramos119 Feb 25, 2025
c34513d
Merge branch 'main' into Noise_Characterization
MaxFroehlich1410 Feb 25, 2025
0790872
characterizer.py (work in progress)
MaxFroehlich1410 Feb 25, 2025
0245b7b
Update characterizer.py
MaxFroehlich1410 Feb 25, 2025
9096728
Update characterizer.py
MaxFroehlich1410 Feb 26, 2025
6e2b98d
Update characterizer.py
MaxFroehlich1410 Feb 26, 2025
fc24da1
Update characterizer.py
MaxFroehlich1410 Feb 27, 2025
8fe948e
updated characterizer.py, reduced A_kn calculation in propagation.py
MaxFroehlich1410 Feb 27, 2025
cf66d5a
characterizer.py updated
MaxFroehlich1410 Feb 27, 2025
d800d2e
Update characterizer.py
MaxFroehlich1410 Feb 27, 2025
b162230
finished A_kn exp vals calculation in characterize.py
MaxFroehlich1410 Feb 27, 2025
5ca20d6
changed back propagation.py, added analytical_gradient_tjm.py (work i…
MaxFroehlich1410 Mar 4, 2025
e29a9e4
Update analytical_gradient_tjm.py
MaxFroehlich1410 Mar 5, 2025
44b710b
scikit_tt_traj implemented
aleramos119 Mar 5, 2025
e9a66de
Added BFGS_tjm.py (work in progress)
MaxFroehlich1410 Mar 5, 2025
ac5974f
Merge branch 'Noise_Characterization' of https://github.com/cda-tum/m…
MaxFroehlich1410 Mar 5, 2025
3f0ebb1
Added TEBD and state vector simulation
MaxFroehlich1410 Mar 6, 2025
cfc6fe0
TEBD debugged
MaxFroehlich1410 Mar 7, 2025
fa9b3e9
added convert_to_vector to MPS class
MaxFroehlich1410 Mar 7, 2025
6a44563
Merge branch 'MPS-to-vector-feature' into Noise_Characterization
MaxFroehlich1410 Mar 7, 2025
d7001d3
qutip_traj computes only the A_kn different than zero
aleramos119 Mar 10, 2025
4988b4b
tjm_traj implemented
aleramos119 Mar 10, 2025
9da7af2
Merge remote-tracking branch 'origin/main' into Noise_Characterization
aleramos119 Mar 12, 2025
c985972
Merge branch 'main' into Noise_Characterization
MaxFroehlich1410 Mar 12, 2025
f5a63fe
Merge branch 'Noise_Characterization' of https://github.com/cda-tum/m…
MaxFroehlich1410 Mar 12, 2025
1742789
work in progress after merge
aleramos119 Mar 13, 2025
dae45a1
Merge branch 'gate_class' into Noise_Characterization
aleramos119 Mar 17, 2025
261577f
Using general gate in tjm_traj
aleramos119 Mar 17, 2025
6556952
Force gammas to be possitive
aleramos119 Mar 18, 2025
7cb8f2f
Added optional beta parameters to ADAM_gradient_descent
aleramos119 Mar 19, 2025
5039960
adjusted Qutip_TJM_compare.py to new rep structure
MaxFroehlich1410 Mar 20, 2025
94e02f4
Added log file to optimization functions
aleramos119 Mar 20, 2025
280b831
Log file bug fix
aleramos119 Mar 20, 2025
da10f8b
adjusted analytical_gardient_tjm to new repo structure + moved noise_…
MaxFroehlich1410 Mar 22, 2025
c346c09
Moved optimization.py to src/mqt/yaqs/noise_char
aleramos119 Mar 25, 2025
0e18091
Log file bug fix
aleramos119 Mar 25, 2025
4be9d95
Added a condition to BFGS to avoid division by zero
aleramos119 Mar 25, 2025
ff92071
Fixed BFGS division by zero condition
aleramos119 Mar 26, 2025
10882e2
Commented line_search for BFGS. Not working
aleramos119 Mar 26, 2025
e5ab9c6
Added labels for file logging
aleramos119 Mar 27, 2025
44e398a
Secant_Penalized_BFGS implemented
aleramos119 Apr 3, 2025
543633f
Added some simulated noise to loss_function for testing
aleramos119 Apr 14, 2025
9b0dcde
Added function call with noise to Secant_Penalized_BFGS
aleramos119 Apr 14, 2025
a91a975
Decreasing learning rate for Secant_Penalized_BFGS
aleramos119 Apr 14, 2025
aee5c8c
Added simulated noise and decaying rate to ADAM_gradient_descent
aleramos119 Apr 15, 2025
788c57b
bayesian_optimization working
aleramos119 Apr 17, 2025
2880a68
user bounds for bayesian_optimization
aleramos119 Apr 22, 2025
b9f9976
acquisition function selection in bayesian optimization
aleramos119 Apr 23, 2025
3b71ce4
Merge remote-tracking branch 'origin/main' into Noise_Characterization
aleramos119 Apr 24, 2025
6f145e4
Some fix after merge
aleramos119 Apr 24, 2025
fd20718
Loss_class implemented
aleramos119 Jun 6, 2025
fa09731
Restart implemented for adam. Needs testing
aleramos119 Jun 17, 2025
06e990c
scikit_tt_traj updated
aleramos119 Jun 20, 2025
f0d0c2d
restart from last restart file
aleramos119 Jun 20, 2025
f932a7c
Merge remote-tracking branch 'origin/main' into Noise_Characterization
aleramos119 Jun 23, 2025
2ee280b
Merge branch 'multi-site-jumps-v2' into Noise_Characterization
aleramos119 Jun 23, 2025
17a85aa
per_site parameters, work in progress
aleramos119 Jun 23, 2025
bab111c
per_site loss function
aleramos119 Jun 23, 2025
6d6e935
Efficient loss evaluation
aleramos119 Jun 24, 2025
88dc32b
Some fixes
aleramos119 Jun 24, 2025
7200dc5
Some fixes
aleramos119 Jun 24, 2025
97c7965
Deleting .pkl files when not restarting
aleramos119 Jun 24, 2025
825a68a
Can choose krylov for scikit_tt solver
aleramos119 Jun 27, 2025
9d2dcf4
Garbage log
aleramos119 Jul 2, 2025
72a1dca
Added unreachable objects
aleramos119 Jul 3, 2025
abb88be
Remove garbage
aleramos119 Jul 3, 2025
54450c2
Merge remote-tracking branch 'origin/Noise_Characterization' into Noi…
aleramos119 Jul 3, 2025
af580ac
Remove garbage
aleramos119 Jul 3, 2025
986a9c3
Multiprocess scikit_tt
aleramos119 Jul 7, 2025
ec99a58
Moved process_k outside scikit_tt_traj
aleramos119 Jul 8, 2025
3cf23af
starmap used
aleramos119 Jul 8, 2025
6c8dae5
Added slurm cpus
aleramos119 Jul 9, 2025
1e15a0c
memory log
aleramos119 Jul 11, 2025
bf5f2a3
Request number cpus scikit_tt_traj
aleramos119 Jul 11, 2025
3b45437
log memory scikit_tt _traj
aleramos119 Jul 11, 2025
0d4dacd
slurm_cpus
aleramos119 Jul 14, 2025
e9e5bd6
Merge remote-tracking branch 'origin/slurm_cpus' into parallalel_scik…
aleramos119 Jul 16, 2025
4760b92
analog sim params
aleramos119 Jul 16, 2025
0836500
Removed memory profiler
aleramos119 Jul 17, 2025
d3d991b
Printing trajectory finished for scikit_tt_traj
aleramos119 Jul 17, 2025
6d741d7
Added np.real
aleramos119 Jul 17, 2025
57edcd2
Bug fix in ncpu selection
aleramos119 Jul 18, 2025
731378e
Merge remote-tracking branch 'origin/parallalel_scikit_tt' into paral…
aleramos119 Jul 18, 2025
f1ef614
Flush result
aleramos119 Jul 18, 2025
3303f86
Using nthreads instead of ncpus
aleramos119 Jul 18, 2025
506db16
Logging time of trajectory k
aleramos119 Jul 18, 2025
2363bc8
Merge branch 'custom_gate' into parallalel_scikit_tt
aleramos119 Jul 20, 2025
5f31d8e
self.post_process bug fixed
aleramos119 Jul 21, 2025
3a711cf
bug fixed in scikit_tt_traj
aleramos119 Jul 22, 2025
9d48e32
Average bug fixed in scikit_tt_traj
aleramos119 Jul 23, 2025
1454c99
performance metric log
aleramos119 Jul 23, 2025
fe1710f
Added constrain that gamma must be < 1
aleramos119 Jul 24, 2025
afe72bb
parameter convergence message
aleramos119 Jul 24, 2025
d30eeae
Merge branch 'parallalel_scikit_tt' into Noise_Characterization
aleramos119 Jul 28, 2025
75cea9f
Added docstrings for propagation
aleramos119 Jul 28, 2025
f5322f8
Log gradients
aleramos119 Jul 29, 2025
ea8db23
write optimal trajectory
aleramos119 Jul 29, 2025
2e455de
Removed scikit_tt
aleramos119 Jul 30, 2025
40f9396
added loss_class docstring
aleramos119 Jul 31, 2025
79185f6
removed unnecessary functions
aleramos119 Jul 31, 2025
6d023a9
changed name to adam_optimizer. added docstring
aleramos119 Jul 31, 2025
6729ec2
removed unnecesary files
aleramos119 Jul 31, 2025
02c6784
removed qutip_traj
aleramos119 Jul 31, 2025
6b2bdf5
removed scikit_tt solver
aleramos119 Jul 31, 2025
05c5ee8
removed scikit_tt_related atributes
aleramos119 Jul 31, 2025
c0a9482
removed unnecessary attributes
aleramos119 Jul 31, 2025
6ebbc1c
Added test_propagation.py
aleramos119 Jul 31, 2025
cf51699
Added test_optimization.py
aleramos119 Jul 31, 2025
9650d6f
pre commit changes
aleramos119 Jul 31, 2025
3de65ac
some fixes
aleramos119 Jul 31, 2025
d8a2748
AnalogSimParams call fix
aleramos119 Jul 31, 2025
cd8b734
mypy passed
aleramos119 Aug 4, 2025
6c00925
ruff fixes
aleramos119 Aug 4, 2025
9286360
test_propagation.py completed
aleramos119 Aug 6, 2025
b5de1de
renamed loss_class_2d to loss_class_2
aleramos119 Aug 6, 2025
29ff6de
docstring
aleramos119 Aug 6, 2025
bc6197c
file path
aleramos119 Aug 6, 2025
56e9f52
ruff changes
aleramos119 Aug 11, 2025
1cfbc2d
changed loss_class_2 to LossClass2
aleramos119 Aug 11, 2025
7026649
precommit passes. tests passed
aleramos119 Aug 12, 2025
cbd6a0b
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 12, 2025
f29740a
Merge remote-tracking branch 'munich-quantum-toolkit/main' into Noise…
aleramos119 Aug 12, 2025
f3d8a4f
Noise name changed
aleramos119 Aug 12, 2025
5b723c4
removed print_to_file from parent class
aleramos119 Aug 15, 2025
f8cdd8a
print_to_file fixed
aleramos119 Aug 15, 2025
e68aa1a
Merge remote-tracking branch 'munich-quantum-toolkit/main' into Noise…
aleramos119 Aug 15, 2025
44085d5
CHanged to pauli_z. Removed .DS_Store
aleramos119 Aug 15, 2025
14f6c85
included test for adam restart
aleramos119 Aug 15, 2025
974935b
Added some tests
aleramos119 Aug 17, 2025
778d422
some error fix
aleramos119 Aug 17, 2025
ab9e7e9
characterizer
aleramos119 Aug 21, 2025
9abeebf
Propagator class
aleramos119 Aug 25, 2025
7c0b389
make_observable_matrix implemented
aleramos119 Aug 25, 2025
6a19e00
Create observable matrix
aleramos119 Aug 25, 2025
fc81ff7
removed tjm_traj
aleramos119 Aug 25, 2025
6d68fa0
added check for noise model
aleramos119 Aug 25, 2025
9bc909f
Returning observables in PropagatorWithGradients call
aleramos119 Aug 27, 2025
1a931e1
added self.n_obs
aleramos119 Aug 27, 2025
cdcdd12
returning d_on_d_gk matrix
aleramos119 Aug 27, 2025
9107502
Added Zero gate
aleramos119 Aug 28, 2025
3a9cf06
Added test to zero gate
aleramos119 Aug 28, 2025
8f152e3
flatten_noise_model
aleramos119 Aug 28, 2025
daded0d
using input_noise_model
aleramos119 Aug 28, 2025
e8395fe
removed make_observable matrix
aleramos119 Aug 28, 2025
8269ebf
Removed LossClass2
aleramos119 Aug 29, 2025
edba728
Removed LossCLass2L
aleramos119 Aug 31, 2025
176fa53
Some precommit fixes
aleramos119 Sep 1, 2025
cdffa1a
finish characterizer.py
aleramos119 Sep 1, 2025
8bc7f38
Changed call to run in propagation
aleramos119 Sep 1, 2025
d7b5761
Removed delete files in set_work_dir
aleramos119 Sep 3, 2025
6550add
Merge remote-tracking branch 'yaqs/main' into characterizer
aleramos119 Sep 9, 2025
57a155c
write_opt_traj -> write_traj
aleramos119 Sep 19, 2025
7c5c595
Merge branch 'write_traj' into characterizer
aleramos119 Sep 19, 2025
dac5ebf
Fixed write_to_file bug
aleramos119 Sep 22, 2025
8139a43
CompactNoiseModel class
aleramos119 Oct 16, 2025
bb69f33
FInished implementation of CompactNoise class
aleramos119 Oct 16, 2025
fa91a51
Some bug fixes
aleramos119 Oct 16, 2025
ec87774
Finished documentation
aleramos119 Oct 19, 2025
5487153
all tests passed
aleramos119 Oct 20, 2025
58a6bae
Merge remote-tracking branch 'munich-quantum-toolkit/main' into chara…
aleramos119 Oct 20, 2025
03bda97
removed noise_model_to_x
aleramos119 Oct 21, 2025
b474930
Added some test for propagation
aleramos119 Oct 21, 2025
01ac5ed
Removed set_times from PropagatorWithGradients
aleramos119 Oct 21, 2025
b7cd691
Removed set_times from PropagatorWithGradients
aleramos119 Oct 21, 2025
0278785
added test_characterizer.py
aleramos119 Oct 21, 2025
ce737ed
passed all pre-commit tests
aleramos119 Oct 21, 2025
7bd6e01
Update .gitignore
aleramos119 Oct 21, 2025
9a1d51f
Update noise_model.py
aleramos119 Oct 21, 2025
6031fcb
removed unnecessary import pathlib
aleramos119 Oct 21, 2025
6d10d3e
Added alias comment
aleramos119 Oct 21, 2025
e681578
Update tests/noise_char/test_optimization.py
aleramos119 Oct 21, 2025
53d07e7
removed unnecessary propagator.run
aleramos119 Oct 21, 2025
c890080
🎨 pre-commit fixes
pre-commit-ci[bot] Oct 21, 2025
0592466
Update docstring in test_propagation.py
aleramos119 Oct 21, 2025
c97c9e7
fixed typo
aleramos119 Oct 21, 2025
770be2f
fixed docstring
aleramos119 Oct 22, 2025
1d24a8a
removed pathlib import
aleramos119 Oct 22, 2025
e063941
Removed redundant array equal
aleramos119 Oct 22, 2025
c9c8ce6
Moved PropagatorWithGradients and LossClass outside
aleramos119 Oct 27, 2025
900dd19
fixed tests. added characterizer_example.md
aleramos119 Oct 28, 2025
b66ad6f
🎨 pre-commit fixes
pre-commit-ci[bot] Oct 28, 2025
e58c188
Some documentation fixes
aleramos119 Oct 28, 2025
3de2c7d
Merge branch 'main' into characterizer
aaronleesander Oct 29, 2025
94c1b87
added gradient descent
aleramos119 Oct 30, 2025
c0893fc
Added return gradient option to loss
aleramos119 Nov 4, 2025
f17f2a5
added post_process
aleramos119 Nov 4, 2025
d1f6f87
Added exponent to Loss
aleramos119 Nov 11, 2025
e4e2a62
Added propagator
aleramos119 Nov 14, 2025
b7ef2c0
added propagator to optimization.py
aleramos119 Nov 14, 2025
5f6069c
some bugs fixed
aleramos119 Nov 14, 2025
2e02f13
added lineal_function_2
aleramos119 Nov 18, 2025
59eb2d6
added lineal_function_400_2
aleramos119 Nov 18, 2025
c4be271
numeric_gradients implemented
aleramos119 Nov 20, 2025
f3094c6
added h to characterizer
aleramos119 Nov 20, 2025
8adc2a7
added clipping for x
aleramos119 Nov 20, 2025
02584a8
added some default options
aleramos119 Nov 20, 2025
90b2001
added numeric gradients in gradient descent
aleramos119 Nov 24, 2025
a8bcd3a
added mcmc algorithm
aleramos119 Nov 27, 2025
6c3f99b
changed max_iterations for max_iter
aleramos119 Nov 27, 2025
65e9450
added x_low and x_up limit for gradient_descent
aleramos119 Nov 27, 2025
6bc08e8
printing optimization settings
aleramos119 Dec 1, 2025
5b17a9f
moved algorithms to optimization_algorithms
aleramos119 Dec 17, 2025
a2a92b6
Removed propagator with gradients
aleramos119 Dec 17, 2025
3006230
finished with pre-commit
aleramos119 Dec 17, 2025
c068cb1
some tests fixed
aleramos119 Dec 17, 2025
6aec7c5
passing all tests
aleramos119 Dec 17, 2025
db24aa1
Merge remote-tracking branch 'munich-quantum-toolkit/main' into gradi…
aleramos119 Dec 17, 2025
3cb9909
fixed dtype in test_gate_library.py
aleramos119 Dec 19, 2025
5744862
removed gradient_descent
aleramos119 Dec 19, 2025
e7fb6db
added test_bayesian.py
aleramos119 Dec 19, 2025
0d6e745
test_fixed
aleramos119 Dec 19, 2025
401d8a1
tests cma and mcmc passed
aleramos119 Dec 23, 2025
3a86741
removed gradient_descent from characterizer.py
aleramos119 Dec 23, 2025
9ca87ec
tests added
aleramos119 Jan 6, 2026
1a71fd8
removed untitled file
aleramos119 Jan 7, 2026
4287ec0
fixed pre-commit errors from test_mcmc
aleramos119 Jan 7, 2026
c7bc658
test_bayesian and test_cma errors fixed
aleramos119 Jan 7, 2026
e59959c
All tests passed
aleramos119 Jan 7, 2026
eb16af4
all tests and pre-commit passed
aleramos119 Jan 7, 2026
ae5c659
Merge remote-tracking branch 'munich-quantum-toolkit/main' into gradi…
aleramos119 Jan 7, 2026
2f4ae57
added dependencies to pyproject.toml
aleramos119 Jan 20, 2026
37e6254
🎨 pre-commit fixes
pre-commit-ci[bot] Jan 20, 2026
95ab06c
Merge remote-tracking branch 'munich-quantum-toolkit/main' into gradi…
aleramos119 Jan 20, 2026
7b4929d
Merge remote-tracking branch 'origin/gradient_free_optimization' into…
aleramos119 Jan 20, 2026
dbaa882
changed to init_ising to ising
aleramos119 Jan 20, 2026
7e0814a
changed versions
aleramos119 Jan 20, 2026
8005500
updated torch version
aleramos119 Jan 20, 2026
7235340
changed torch version
aleramos119 Jan 20, 2026
85dfa6e
fixed torch version
aleramos119 Jan 20, 2026
f1e7769
restricting python to <=3.12
aleramos119 Jan 20, 2026
07fbb61
fixing botorch and gpytorch versions
aleramos119 Jan 20, 2026
250c142
added pyro to dependencies
aleramos119 Jan 20, 2026
73a8951
Merge remote-tracking branch 'munich-quantum-toolkit/main' into gradi…
aleramos119 Jan 20, 2026
b3fb82a
fixed uv.lock
aleramos119 Jan 20, 2026
ecc4b16
Merge remote-tracking branch 'munich-quantum-toolkit/main' into gradi…
aleramos119 Mar 3, 2026
c3d7dc8
🎨 pre-commit fixes
pre-commit-ci[bot] Mar 3, 2026
5ae8e1d
precommit and tests passed
aleramos119 Mar 3, 2026
e2c02a9
Merge remote-tracking branch 'origin/gradient_free_optimization' into…
aleramos119 Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions docs/examples/characterizer_example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Characterizer example

This document contains the example script `characterizer_example.py` converted to Markdown. It shows how to set up a simple Ising Hamiltonian, generate a reference trajectory with a given noise model, build a LossClass and Characterizer, and run the optimizer.

## Requirements

- numpy
- mqt.yaqs package (propagation, optimization, characterizer, core.data_structures)
- A working environment where PropagatorWithGradients can run (the example uses the package's propagator)

## Usage

Copy the Python code block below into a `.py` file and run it, or execute the cells if using a notebook.

```python
import numpy as np
from pathlib import Path

from mqt.yaqs.noise_char.propagation import PropagatorWithGradients
from mqt.yaqs.noise_char.optimization import LossClass
from mqt.yaqs.noise_char.characterizer import Characterizer
Comment on lines +19 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the actual module structure and class locations
echo "=== Checking noise_char module structure ==="
find . -path "*/mqt/yaqs/noise_char/*.py" -type f | head -20

echo ""
echo "=== Searching for LossClass definition ==="
rg -n "class LossClass" --type py 2>/dev/null || echo "No LossClass found"

echo ""
echo "=== Searching for PropagatorWithGradients definition ==="
rg -n "class PropagatorWithGradients" --type py 2>/dev/null || echo "No PropagatorWithGradients found"

echo ""
echo "=== Searching for Propagator definition ==="
rg -n "class Propagator" --type py 2>/dev/null

echo ""
echo "=== Checking optimization.py content ==="
fd optimization.py --type f | xargs cat -n 2>/dev/null | head -50

echo ""
echo "=== Checking loss.py content if it exists ==="
fd loss.py --type f | xargs cat -n 2>/dev/null | head -50

echo ""
echo "=== Checking propagation.py content ==="
fd propagation.py --type f | xargs cat -n 2>/dev/null | head -80

Repository: munich-quantum-toolkit/yaqs

Length of output: 8425


Fix incorrect import paths on lines 19-21.

The imports contain two errors:

  1. LossClass should be imported from mqt.yaqs.noise_char.loss, not from a non-existent mqt.yaqs.noise_char.optimization module.
  2. PropagatorWithGradients does not exist; the correct class is Propagator from mqt.yaqs.noise_char.propagation.

Correct imports should be:

from mqt.yaqs.noise_char.propagation import Propagator
from mqt.yaqs.noise_char.loss import LossClass
from mqt.yaqs.noise_char.characterizer import Characterizer
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/characterizer_example.md` around lines 19 - 21, The imports are
wrong: replace the non-existent PropagatorWithGradients and wrong module for
LossClass; import Propagator from mqt.yaqs.noise_char.propagation (use symbol
Propagator instead of PropagatorWithGradients) and import LossClass from
mqt.yaqs.noise_char.loss (not mqt.yaqs.noise_char.optimization), keeping the
existing Characterizer import from mqt.yaqs.noise_char.characterizer.


from mqt.yaqs.core.data_structures.networks import MPO, MPS
from mqt.yaqs.core.data_structures.noise_model import CompactNoiseModel
from mqt.yaqs.core.data_structures.simulation_parameters import (
AnalogSimParams,
Observable,
)
from mqt.yaqs.core.libraries.gate_library import X, Y, Z, Create, Destroy

if __name__ == "__main__":
work_dir = "test/scikit_characterizer/"
work_dir_path = Path(work_dir)
work_dir_path.mkdir(parents=True, exist_ok=True)

Comment on lines +32 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Prefer consistent use of Path objects.

Line 33 creates a string path, Line 34 converts it to a Path object, but Line 86 continues to use the string version. For consistency and cross-platform compatibility, prefer using work_dir_path throughout.

♻️ Suggested refactor for consistent Path usage
-    work_dir = "test/scikit_characterizer/"
-    work_dir_path = Path(work_dir)
+    work_dir_path = Path("test/scikit_characterizer/")
     work_dir_path.mkdir(parents=True, exist_ok=True)

And update Line 86:

-        work_dir + "gammas.txt", ref_noise_model.strength_list, header="##", fmt="%.6f"
+        work_dir_path / "gammas.txt", ref_noise_model.strength_list, header="##", fmt="%.6f"

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @docs/examples/characterizer_example.md around lines 33 - 36, The code mixes
a string path variable work_dir with a Path object work_dir_path; replace all
subsequent uses of the string (notably the usage around the original Line 86) to
use work_dir_path for consistency and cross-platform correctness, and where an
API requires a string pass work_dir_path.as_posix() or str(work_dir_path);
update any file/directory operations, joins, or reads/writes to reference
work_dir_path (or its string form when necessary).

# Defining Hamiltonian and observable list
L = 2
J = 1
g = 0.5

H_0 = MPO()
H_0.init_ising(L, J, g)

# Define the initial state
init_state = MPS(L, state="zeros")

obs_list = [Observable(X(), site) for site in range(L)]

noise_operator = "pauli_y"

# Defining simulation parameters
T = 3
dt = 0.1
N = 1000
max_bond_dim = 8
threshold = 1e-6
order = 1

sim_params = AnalogSimParams(
observables=obs_list,
elapsed_time=T,
dt=dt,
num_traj=N,
max_bond_dim=max_bond_dim,
threshold=threshold,
order=order,
sample_timesteps=True,
)

# Defining reference noise model and reference trajectory
gamma_reference = 0.1

ref_noise_model = CompactNoiseModel(
[
{
"name": noise_operator,
"sites": [i for i in range(L)],
"strength": gamma_reference,
Comment on lines +77 to +78
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Simplify list comprehension.

The pattern [i for i in range(L)] is equivalent to list(range(L)), which is more idiomatic and slightly more performant.

♻️ Suggested simplification
-                "sites": [i for i in range(L)],
+                "sites": list(range(L)),

Similarly for line 113:

-                "sites": [i for i in range(L)],
+                "sites": list(range(L)),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"sites": [i for i in range(L)],
"strength": gamma_reference,
"sites": list(range(L)),
"strength": gamma_reference,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/characterizer_example.md` around lines 77 - 78, Replace the
explicit list comprehension [i for i in range(L)] with the idiomatic
list(range(L)) wherever it appears (e.g., the dict entry with key "sites" that
uses L and gamma_reference and the other similar occurrence later in the file),
updating both instances to use list(range(L)) for clarity and minor performance
improvement.

}
]
)

# Write reference gammas to file
np.savetxt(
work_dir + "gammas.txt", ref_noise_model.strength_list, header="##", fmt="%.6f"
)

propagator = PropagatorWithGradients(
sim_params=sim_params,
hamiltonian=H_0,
compact_noise_model=ref_noise_model,
init_state=init_state,
)

propagator.set_observable_list(obs_list)

print("Computing reference trajectory ... ")
propagator.run(ref_noise_model)
ref_traj = propagator.obs_traj
print("Reference trajectory computed.")

# Optimizing the model
gamma_guess = 0.4

sim_params.num_traj = (
300 # Reducing the number of trajectories for the optimization
)

guess_noise_model = CompactNoiseModel(
[
{
"name": noise_operator,
"sites": [i for i in range(L)],
"strength": gamma_guess,
}
]
)

opt_propagator = PropagatorWithGradients(
sim_params=sim_params,
hamiltonian=H_0,
compact_noise_model=guess_noise_model,
init_state=init_state,
)

loss = LossClass(
ref_traj=ref_traj,
traj_gradients=opt_propagator,
working_dir=work_dir,
print_to_file=True,
)

characterizer = Characterizer(
traj_gradients=opt_propagator, init_guess=guess_noise_model, loss=loss
)

print("Optimizing ... ")
characterizer.adam_optimize(max_iterations=50)
print("Optimization completed.")
Comment on lines +137 to +139
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Clarify that this example uses gradient-based optimization.

The PR title and objectives emphasize "Gradient-Free Noise Characterization," but this example demonstrates adam_optimize, which is a gradient-based method. While it's fine to include gradient-based examples, the documentation should clarify this distinction or show gradient-free alternatives (CMA, MCMC, Bayesian) as well.

Consider adding a note before Line 138:

Note: This example uses the Adam optimizer, which is a gradient-based method. For gradient-free optimization, you can use:
- `characterizer.cma_optimize(max_iterations=50)`
- `characterizer.mcmc_optimize(max_iterations=50)`
- `characterizer.bayesian_optimize(max_iterations=50)`
🤖 Prompt for AI Agents
In @docs/examples/characterizer_example.md around lines 138 - 140, Add a short
clarifying note before the example's optimization block stating that
adam_optimize is a gradient-based method and provide the gradient-free
alternatives to use (cma_optimize, mcmc_optimize, bayesian_optimize) with the
same max_iterations argument; reference the existing call to
characterizer.adam_optimize(max_iterations=50) and suggest replacing or showing
alternatives like characterizer.cma_optimize(max_iterations=50),
characterizer.mcmc_optimize(max_iterations=50), or
characterizer.bayesian_optimize(max_iterations=50) so readers understand the
distinction.

```
2 changes: 1 addition & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
nox.options.default_venv_backend = "uv"


PYTHON_ALL_VERSIONS = ["3.10", "3.11", "3.12", "3.13", "3.14"]
PYTHON_ALL_VERSIONS = ["3.10", "3.11", "3.12"]

if os.environ.get("CI", None):
nox.options.error_on_missing_interpreters = True
Expand Down
12 changes: 10 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
"Typing :: Typed",
]
Expand All @@ -49,6 +47,16 @@ dependencies = [
"qiskit>=1.3.0; python_version >= '3.13'",
"opt-einsum>=3.4.0",
"tqdm>=4.67.1",
"cma>=4.0.0",

"torch>=2.1.0; python_version < '3.12'",
"torch>=2.4.0; python_version >= '3.12' and python_version < '3.13'",


"botorch>=0.16.0; python_version < '3.13'",
"gpytorch>=1.14.2; python_version < '3.13'",
Comment on lines +50 to +57
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find the pyproject.toml file in the repository
find . -name "pyproject.toml" -type f | head -5

Repository: munich-quantum-toolkit/yaqs

Length of output: 87


🏁 Script executed:

# Read the pyproject.toml file to verify the dependency markers and requires-python
cat -n ./pyproject.toml

Repository: munich-quantum-toolkit/yaqs

Length of output: 7179


🏁 Script executed:

# Check if torch, botorch, gpytorch are imported anywhere in the source code
find src -name "*.py" -type f | head -20

Repository: munich-quantum-toolkit/yaqs

Length of output: 906


🏁 Script executed:

# Search for imports of torch, botorch, and gpytorch
rg "import torch|from torch|import botorch|from botorch|import gpytorch|from gpytorch" src/ --type py

Repository: munich-quantum-toolkit/yaqs

Length of output: 870


🏁 Script executed:

# Check the noise_char module to see if torch/botorch/gpytorch imports are guarded
cat -n src/mqt/yaqs/noise_char/optimization_algorithms/gradient_free/bayesian.py | head -50

Repository: munich-quantum-toolkit/yaqs

Length of output: 1988


🏁 Script executed:

# Check if there's a guard around the imports in the noise_char module's __init__.py
find src/mqt/yaqs/noise_char -name "__init__.py" | xargs cat -n

Repository: munich-quantum-toolkit/yaqs

Length of output: 1230


🏁 Script executed:

# Find the actual noise_char __init__.py and check imports
find src/mqt/yaqs/noise_char -type f -name "*.py" | xargs ls -la

Repository: munich-quantum-toolkit/yaqs

Length of output: 1261


🏁 Script executed:

# Check the noise_char __init__.py to see what's exposed
cat -n src/mqt/yaqs/noise_char/__init__.py

Repository: munich-quantum-toolkit/yaqs

Length of output: 360


🏁 Script executed:

# Check the characterizer.py to see if it imports bayesian directly
cat -n src/mqt/yaqs/noise_char/characterizer.py | head -80

Repository: munich-quantum-toolkit/yaqs

Length of output: 3266


🏁 Script executed:

# Check if the imports in characterizer.py are guarded, and check where bayesian_opt is called
cat -n src/mqt/yaqs/noise_char/characterizer.py | grep -A 5 -B 5 "bayesian_opt"

Repository: munich-quantum-toolkit/yaqs

Length of output: 1429


🏁 Script executed:

# Check if there are any conditional/try-except imports around torch/botorch/gpytorch
rg "try:|except|ImportError" src/mqt/yaqs/noise_char/optimization_algorithms/gradient_free/bayesian.py -B 2 -A 2

Repository: munich-quantum-toolkit/yaqs

Length of output: 53


🏁 Script executed:

# Verify that the imports at the top of bayesian.py are not guarded
head -35 src/mqt/yaqs/noise_char/optimization_algorithms/gradient_free/bayesian.py

Repository: munich-quantum-toolkit/yaqs

Length of output: 1115


Align Python version support: either cap requires-python to <3.13 or add conditional imports for optimization dependencies.

torch, botorch, and gpytorch are excluded for Python ≥3.13 (via dependency markers), but classifiers only list 3.10–3.12 while requires-python = ">=3.10" technically permits 3.13+. Additionally, these libraries are imported unguarded at module level in src/mqt/yaqs/noise_char/optimization_algorithms/gradient_free/bayesian.py, so any user installing on Python 3.13+ will encounter ModuleNotFoundError when accessing Bayesian optimization.

Either:

  1. Cap requires-python = ">=3.10,<3.13" to match classifiers and declared support, or
  2. Wrap torch/botorch/gpytorch imports in try-except blocks and handle gracefully for 3.13+
🤖 Prompt for AI Agents
In `@pyproject.toml` around lines 50 - 57, Align the Python support by either
tightening pyproject's requires-python to ">=3.10,<3.13" (so dependency markers
for "torch", "botorch", "gpytorch" remain valid) or make the optimization deps
optional: in
src/mqt/yaqs/noise_char/optimization_algorithms/gradient_free/bayesian.py guard
module-level imports of torch, botorch and gpytorch with try/except ImportError
and raise a clear, descriptive error only when Bayesian functions/classes (the
ones that use these libs) are invoked; reference the requires-python entry in
pyproject.toml and the import sites for torch, botorch, gpytorch in bayesian.py
to locate and apply the change.

"pyro-ppl>=1.9.0; python_version < '3.13'",

"threadpoolctl>=3.1.0",
"numba>=0.61.0",
"numba>=0.63.0; python_version >= '3.14'",
Expand Down
87 changes: 87 additions & 0 deletions src/mqt/yaqs/core/data_structures/noise_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import numpy as np
from scipy.stats import truncnorm

from ..libraries.gate_library import GateLibrary
from ..libraries.noise_library import NoiseLibrary

if TYPE_CHECKING:
Expand Down Expand Up @@ -262,3 +263,89 @@ def get_operator(name: str) -> NDArray[np.complex128]:

operator: BaseGate = operator_class()
return operator.matrix


class CompactNoiseModel:
"""A class to represent a compact noise model with multi-site noise processes."""

def __init__(self, compact_processes: list[dict[str, Any]] | None = None) -> None:
"""Initialize the compact noise model.

Parameters.
----------
compact_processes : list[dict[str, Any]] | None, optional
A list of compact noise process specifications or None. Each process dict
must contain the following keys:
- "name" (str): name of a noise process available from GateLibrary.
- "sites" (iterable[int]): indices of sites the compact process acts on.
- "strength" (numeric): strength/amplitude of the noise process.
Behavior
--------
- If compact_processes is provided, a deep copy is stored in
self.compact_processes to avoid external mutation; otherwise an empty list
is used.
- Each process dict is validated:
- Must contain the keys "name", "sites", and "strength".
- The GateLibrary entry for the given "name" must exist and represent a
1-site interaction (GateLibrary.<name>().interaction == 1).
Violations raise AssertionError or ValueError.
- The compact processes are expanded into single-site process entries:
- For each site in a compact process, an expanded dict
{"name": name, "sites": [site], "strength": strength} is appended to
self.expanded_processes.
- For each expanded entry, the index of the originating compact process
is appended to self.index_list.
- A NoiseModel is created from the expanded processes and stored as
self.expanded_noise_model.
Attributes set
--------------
self.compact_processes : list[dict[str, Any]]
Deep-copied list of compact process definitions (or empty list).
self.expanded_processes : list[dict[str, Any]]
List of per-site expanded process dictionaries.
self.index_list : list[int]
Mapping from each expanded process to the index of its original compact
process in self.compact_processes.
self.expanded_noise_model : NoiseModel
NoiseModel constructed from self.expanded_processes.
self.strength_list : np.ndarray
Array of strengths corresponding to each compact process.

Raises:
------
ValueError: If the named gate is not found in GateLibrary. The exception message is:
"Gate '<name>' not found in GateLibrary".

Notes:
-----
- This initializer assumes GateLibrary and NoiseModel are available in the
surrounding module scope.
- The method performs input validation and expansion to ensure downstream
code can work with single-site noise process descriptions.
"""
self.compact_processes: list[dict[str, Any]] = (
copy.deepcopy(compact_processes) if compact_processes is not None else []
)

self.expanded_processes: list[dict[str, Any]] = []

self.index_list: list[int] = []

for i, proc in enumerate(self.compact_processes):
assert "name" in proc, "Each process must have a 'name' key"
name = proc["name"]
if not hasattr(GateLibrary, name):
msg = f"Gate '{name}' not found in GateLibrary"
raise ValueError(msg)
msg = "Only 1-site noise processes are supported in CompactNoiseModel"
assert getattr(GateLibrary, name)().interaction == 1, msg
assert "sites" in proc, "Each process must have a 'sites' key"
assert "strength" in proc, "Each process must have a 'strength' key"

for site in proc["sites"]:
self.expanded_processes.append({"name": proc["name"], "sites": [site], "strength": proc["strength"]})
self.index_list.append(i)
Comment on lines +334 to +347
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Validation order could be optimized to fail fast.

Currently, the code validates name key presence (line 237), then checks GateLibrary (line 239), then validates interaction (line 243), and finally checks sites and strength (lines 244-245). If sites or strength are missing, the code will still instantiate the gate before failing. Consider checking all required keys first.

Proposed reordering for fail-fast validation
         for i, proc in enumerate(self.compact_processes):
             assert "name" in proc, "Each process must have a 'name' key"
+            assert "sites" in proc, "Each process must have a 'sites' key"
+            assert "strength" in proc, "Each process must have a 'strength' key"
             name = proc["name"]
             if not hasattr(GateLibrary, name):
                 msg = f"Gate '{name}' not found in GateLibrary"
                 raise ValueError(msg)
             msg = "Only 1-site noise processes are supported in CompactNoiseModel"
             assert getattr(GateLibrary, name)().interaction == 1, msg
-            assert "sites" in proc, "Each process must have a 'sites' key"
-            assert "strength" in proc, "Each process must have a 'strength' key"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for i, proc in enumerate(self.compact_processes):
assert "name" in proc, "Each process must have a 'name' key"
name = proc["name"]
if not hasattr(GateLibrary, name):
msg = f"Gate '{name}' not found in GateLibrary"
raise ValueError(msg)
msg = "Only 1-site noise processes are supported in CompactNoiseModel"
assert getattr(GateLibrary, name)().interaction == 1, msg
assert "sites" in proc, "Each process must have a 'sites' key"
assert "strength" in proc, "Each process must have a 'strength' key"
for site in proc["sites"]:
self.expanded_processes.append({"name": proc["name"], "sites": [site], "strength": proc["strength"]})
self.index_list.append(i)
for i, proc in enumerate(self.compact_processes):
assert "name" in proc, "Each process must have a 'name' key"
assert "sites" in proc, "Each process must have a 'sites' key"
assert "strength" in proc, "Each process must have a 'strength' key"
name = proc["name"]
if not hasattr(GateLibrary, name):
msg = f"Gate '{name}' not found in GateLibrary"
raise ValueError(msg)
msg = "Only 1-site noise processes are supported in CompactNoiseModel"
assert getattr(GateLibrary, name)().interaction == 1, msg
for site in proc["sites"]:
self.expanded_processes.append({"name": proc["name"], "sites": [site], "strength": proc["strength"]})
self.index_list.append(i)
🤖 Prompt for AI Agents
In @src/mqt/yaqs/core/data_structures/noise_model.py around lines 236 - 249, The
loop over self.compact_processes should validate required keys before touching
GateLibrary or instantiating gates: first assert "name", "sites", and "strength"
are present on proc, then check GateLibrary membership for proc["name"], then
retrieve the gate class once (e.g., cls = getattr(GateLibrary, name)) and assert
cls().interaction == 1 before expanding sites into self.expanded_processes and
appending to self.index_list; reorder the checks in the loop to perform key
presence checks first to fail fast and avoid creating gate instances when keys
are missing.


self.strength_list: np.ndarray = np.array([proc["strength"] for proc in self.compact_processes])

self.expanded_noise_model: NoiseModel = NoiseModel(self.expanded_processes)
39 changes: 39 additions & 0 deletions src/mqt/yaqs/core/libraries/gate_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,15 @@ def id(cls) -> Id:
"""
return Id()

@classmethod
def zero(cls) -> Zero:
"""Returns the Zero gate.

Returns:
Zero: An instance of the Zero gate.
"""
return Zero()

@classmethod
def sx(cls) -> SX:
"""Returns the SX gate.
Expand Down Expand Up @@ -780,6 +789,28 @@ def __init__(self) -> None:
super().__init__(mat)


class Zero(BaseGate):
"""Class representing the Zero gate.

Attributes:
name: The name of the gate ("zero").
matrix: The 2x2 zero matrix.
interaction: The interaction level (1 for single-qubit gates).
tensor: The tensor representation of the gate (same as the matrix).

Methods:
set_sites(*sites: int) -> None:
Sets the site(s) where the gate is applied.
"""

name = "zero"

def __init__(self) -> None:
"""Initializes the Zero gate."""
mat = np.array([[0, 0], [0, 0]])
super().__init__(mat)


class SX(BaseGate):
"""Class representing the square-root X (SX) gate.

Expand Down Expand Up @@ -1739,3 +1770,11 @@ class GateLibrary:
schmidt_spectrum = SchmidtSpectrum

custom = BaseGate
zero = Zero

# Added aliases to be compatible with naming conventions in noise models
raising = Create
lowering = Destroy
pauli_z = Z
pauli_x = X
pauli_y = Y
8 changes: 8 additions & 0 deletions src/mqt/yaqs/noise_char/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2025 - 2026 Chair for Design Automation, TUM
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

"""This module contains the optimization routines for noise characterization."""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Docstring scope is incomplete.

The module docstring describes only "optimization routines," but per the PR context, this module provides a comprehensive noise characterization subsystem including propagators, loss evaluators, a high-level Characterizer orchestrator, and multiple optimization strategies (both gradient-based and gradient-free). Consider revising the docstring to reflect the broader scope.

🤖 Prompt for AI Agents
In @src/mqt/yaqs/noise_char/__init__.py at line 8, The module docstring is too
narrow—update the top-level docstring in src/mqt/yaqs/noise_char/__init__.py to
describe the full noise characterization subsystem (not just "optimization
routines"): mention that the module exports propagators, loss evaluators, the
high-level Characterizer orchestrator, and multiple optimization strategies
(gradient-based and gradient-free), and briefly state their roles so readers
know the available APIs and responsibilities.

Loading
Loading