diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4066fde8..afa74f02 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ on: branches: [ 'main', 'dev' ] jobs: - lint: + test: name: Run Unit Tests runs-on: [ 'ubuntu-latest' ] env: @@ -33,7 +33,14 @@ jobs: - name: Install Dependencies run: pip install -r .settings/requirements_full.txt - - name: Run tests with unittest - run: python -m unittest discover . + - name: Run Unit Tests + run: python -m unittest discover . > unittest_results.log + + - name: Upload Test Logs + if: always() + uses: actions/upload-artifact@v3 + with: + name: unittest-logs + path: unittest_results.log diff --git a/.settings/module_db.json b/.settings/module_db.json index 20ce888f..a6fade90 100644 --- a/.settings/module_db.json +++ b/.settings/module_db.json @@ -1,3612 +1,3612 @@ -{ - "build_number": 16, - "build_date": "03-12-2024 10:33:07", - "git_revision_number": "5dd793e3a63cae9acd48fc083569f9ba20615e4c", - "modules": [ - { - "name": "PVC", - "class": "PVC", - "module": "modules.applications.optimization.PVC.PVC", - "submodules": [ - { - "name": "Ising", - "class": "Ising", - "args": {}, - "module": "modules.applications.optimization.PVC.mappings.ISING", - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - }, - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "dimod", - "version": "0.12.17" - }, - { - "name": "networkx", - "version": "3.2.1" - } - ], - "submodules": [ - { - "name": "QAOA", - "class": "QAOA", - "args": {}, - "module": "modules.solvers.QAOA", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "scipy", - "version": "1.12.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "LocalSimulator", - "class": "LocalSimulator", - "args": { - "device_name": "LocalSimulator" - }, - "module": "modules.devices.braket.LocalSimulator", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", - "class": "SV1", - "args": { - "device_name": "SV1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" - }, - "module": "modules.devices.braket.SV1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", - "class": "TN1", - "args": { - "device_name": "TN1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" - }, - "module": "modules.devices.braket.TN1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", - "class": "Ionq", - "args": { - "device_name": "ionQ", - "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" - }, - "module": "modules.devices.braket.Ionq", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", - "class": "Rigetti", - "args": { - "device_name": "Rigetti Aspen-9", - "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" - }, - "module": "modules.devices.braket.Rigetti", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - } - ] - }, - { - "name": "PennylaneQAOA", - "class": "PennylaneQAOA", - "args": {}, - "module": "modules.solvers.PennylaneQAOA", - "requirements": [ - { - "name": "pennylane", - "version": "0.37.0" - }, - { - "name": "pennylane-lightning", - "version": "0.38.0" - }, - { - "name": "amazon-braket-pennylane-plugin", - "version": "1.30.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", - "class": "SV1", - "args": { - "device_name": "SV1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" - }, - "module": "modules.devices.braket.SV1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", - "class": "TN1", - "args": { - "device_name": "TN1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" - }, - "module": "modules.devices.braket.TN1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", - "class": "Ionq", - "args": { - "device_name": "ionq", - "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" - }, - "module": "modules.devices.braket.Ionq", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", - "class": "Rigetti", - "args": { - "device_name": "Rigetti", - "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" - }, - "module": "modules.devices.braket.Rigetti", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy", - "class": "OQC", - "args": { - "device_name": "OQC", - "arn": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" - }, - "module": "modules.devices.braket.OQC", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "braket.local.qubit", - "class": "HelperClass", - "args": { - "device_name": "braket.local.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "default.qubit", - "class": "HelperClass", - "args": { - "device_name": "default.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "default.qubit.autograd", - "class": "HelperClass", - "args": { - "device_name": "default.qubit.autograd" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "qulacs.simulator", - "class": "HelperClass", - "args": { - "device_name": "qulacs.simulator" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "lightning.gpu", - "class": "HelperClass", - "args": { - "device_name": "lightning.gpu" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "lightning.qubit", - "class": "HelperClass", - "args": { - "device_name": "lightning.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - } - ] - } - ] - }, - { - "name": "QUBO", - "class": "QUBO", - "args": {}, - "module": "modules.applications.optimization.PVC.mappings.QUBO", - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - } - ], - "submodules": [ - { - "name": "Annealer", - "class": "Annealer", - "args": {}, - "module": "modules.solvers.Annealer", - "requirements": [], - "submodules": [ - { - "name": "Simulated Annealer", - "class": "SimulatedAnnealingSampler", - "args": {}, - "module": "modules.devices.SimulatedAnnealingSampler", - "requirements": [ - { - "name": "dwave-samplers", - "version": "1.3.0" - } - ], - "submodules": [] - } - ] - } - ] - }, - { - "name": "GreedyClassicalPVC", - "class": "GreedyClassicalPVC", - "args": {}, - "module": "modules.solvers.GreedyClassicalPVC", - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - } - ], - "submodules": [ - { - "name": "Local", - "class": "Local", - "args": {}, - "module": "modules.devices.Local", - "requirements": [], - "submodules": [] - } - ] - }, - { - "name": "ReverseGreedyClassicalPVC", - "class": "ReverseGreedyClassicalPVC", - "args": {}, - "module": "modules.solvers.ReverseGreedyClassicalPVC", - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - } - ], - "submodules": [ - { - "name": "Local", - "class": "Local", - "args": {}, - "module": "modules.devices.Local", - "requirements": [], - "submodules": [] - } - ] - }, - { - "name": "RandomPVC", - "class": "RandomPVC", - "args": {}, - "module": "modules.solvers.RandomClassicalPVC", - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - } - ], - "submodules": [ - { - "name": "Local", - "class": "Local", - "args": {}, - "module": "modules.devices.Local", - "requirements": [], - "submodules": [] - } - ] - } - ], - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ] - }, - { - "name": "SAT", - "class": "SAT", - "module": "modules.applications.optimization.SAT.SAT", - "submodules": [ - { - "name": "QubovertQUBO", - "class": "QubovertQUBO", - "args": {}, - "module": "modules.applications.optimization.SAT.mappings.QubovertQUBO", - "requirements": [ - { - "name": "nnf", - "version": "0.4.1" - }, - { - "name": "qubovert", - "version": "1.2.5" - } - ], - "submodules": [ - { - "name": "Annealer", - "class": "Annealer", - "args": {}, - "module": "modules.solvers.Annealer", - "requirements": [], - "submodules": [ - { - "name": "Simulated Annealer", - "class": "SimulatedAnnealingSampler", - "args": {}, - "module": "modules.devices.SimulatedAnnealingSampler", - "requirements": [ - { - "name": "dwave-samplers", - "version": "1.3.0" - } - ], - "submodules": [] - } - ] - } - ] - }, - { - "name": "Direct", - "class": "Direct", - "args": {}, - "module": "modules.applications.optimization.SAT.mappings.Direct", - "requirements": [ - { - "name": "nnf", - "version": "0.4.1" - }, - { - "name": "python-sat", - "version": "1.8.dev13" - } - ], - "submodules": [ - { - "name": "ClassicalSAT", - "class": "ClassicalSAT", - "args": {}, - "module": "modules.solvers.ClassicalSAT", - "requirements": [ - { - "name": "python-sat", - "version": "1.8.dev13" - } - ], - "submodules": [ - { - "name": "Local", - "class": "Local", - "args": {}, - "module": "modules.devices.Local", - "requirements": [], - "submodules": [] - } - ] - }, - { - "name": "RandomSAT", - "class": "RandomSAT", - "args": {}, - "module": "modules.solvers.RandomClassicalSAT", - "requirements": [ - { - "name": "python-sat", - "version": "1.8.dev13" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "Local", - "class": "Local", - "args": {}, - "module": "modules.devices.Local", - "requirements": [], - "submodules": [] - } - ] - } - ] - }, - { - "name": "ChoiQUBO", - "class": "ChoiQUBO", - "args": {}, - "module": "modules.applications.optimization.SAT.mappings.ChoiQUBO", - "requirements": [ - { - "name": "nnf", - "version": "0.4.1" - } - ], - "submodules": [ - { - "name": "Annealer", - "class": "Annealer", - "args": {}, - "module": "modules.solvers.Annealer", - "requirements": [], - "submodules": [ - { - "name": "Simulated Annealer", - "class": "SimulatedAnnealingSampler", - "args": {}, - "module": "modules.devices.SimulatedAnnealingSampler", - "requirements": [ - { - "name": "dwave-samplers", - "version": "1.3.0" - } - ], - "submodules": [] - } - ] - } - ] - }, - { - "name": "DinneenQUBO", - "class": "DinneenQUBO", - "args": {}, - "module": "modules.applications.optimization.SAT.mappings.DinneenQUBO", - "requirements": [ - { - "name": "nnf", - "version": "0.4.1" - } - ], - "submodules": [ - { - "name": "Annealer", - "class": "Annealer", - "args": {}, - "module": "modules.solvers.Annealer", - "requirements": [], - "submodules": [ - { - "name": "Simulated Annealer", - "class": "SimulatedAnnealingSampler", - "args": {}, - "module": "modules.devices.SimulatedAnnealingSampler", - "requirements": [ - { - "name": "dwave-samplers", - "version": "1.3.0" - } - ], - "submodules": [] - } - ] - } - ] - }, - { - "name": "ChoiIsing", - "class": "ChoiIsing", - "args": {}, - "module": "modules.applications.optimization.SAT.mappings.ChoiISING", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "dimod", - "version": "0.12.17" - }, - { - "name": "nnf", - "version": "0.4.1" - } - ], - "submodules": [ - { - "name": "QAOA", - "class": "QAOA", - "args": {}, - "module": "modules.solvers.QAOA", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "scipy", - "version": "1.12.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "LocalSimulator", - "class": "LocalSimulator", - "args": { - "device_name": "LocalSimulator" - }, - "module": "modules.devices.braket.LocalSimulator", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", - "class": "SV1", - "args": { - "device_name": "SV1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" - }, - "module": "modules.devices.braket.SV1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", - "class": "TN1", - "args": { - "device_name": "TN1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" - }, - "module": "modules.devices.braket.TN1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", - "class": "Ionq", - "args": { - "device_name": "ionQ", - "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" - }, - "module": "modules.devices.braket.Ionq", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", - "class": "Rigetti", - "args": { - "device_name": "Rigetti Aspen-9", - "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" - }, - "module": "modules.devices.braket.Rigetti", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - } - ] - }, - { - "name": "PennylaneQAOA", - "class": "PennylaneQAOA", - "args": {}, - "module": "modules.solvers.PennylaneQAOA", - "requirements": [ - { - "name": "pennylane", - "version": "0.37.0" - }, - { - "name": "pennylane-lightning", - "version": "0.38.0" - }, - { - "name": "amazon-braket-pennylane-plugin", - "version": "1.30.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", - "class": "SV1", - "args": { - "device_name": "SV1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" - }, - "module": "modules.devices.braket.SV1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", - "class": "TN1", - "args": { - "device_name": "TN1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" - }, - "module": "modules.devices.braket.TN1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", - "class": "Ionq", - "args": { - "device_name": "ionq", - "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" - }, - "module": "modules.devices.braket.Ionq", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", - "class": "Rigetti", - "args": { - "device_name": "Rigetti", - "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" - }, - "module": "modules.devices.braket.Rigetti", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy", - "class": "OQC", - "args": { - "device_name": "OQC", - "arn": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" - }, - "module": "modules.devices.braket.OQC", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "braket.local.qubit", - "class": "HelperClass", - "args": { - "device_name": "braket.local.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "default.qubit", - "class": "HelperClass", - "args": { - "device_name": "default.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "default.qubit.autograd", - "class": "HelperClass", - "args": { - "device_name": "default.qubit.autograd" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "qulacs.simulator", - "class": "HelperClass", - "args": { - "device_name": "qulacs.simulator" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "lightning.gpu", - "class": "HelperClass", - "args": { - "device_name": "lightning.gpu" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "lightning.qubit", - "class": "HelperClass", - "args": { - "device_name": "lightning.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - } - ] - } - ] - }, - { - "name": "DinneenIsing", - "class": "DinneenIsing", - "args": {}, - "module": "modules.applications.optimization.SAT.mappings.DinneenISING", - "requirements": [ - { - "name": "nnf", - "version": "0.4.1" - }, - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "dimod", - "version": "0.12.17" - }, - { - "name": "nnf", - "version": "0.4.1" - } - ], - "submodules": [ - { - "name": "QAOA", - "class": "QAOA", - "args": {}, - "module": "modules.solvers.QAOA", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "scipy", - "version": "1.12.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "LocalSimulator", - "class": "LocalSimulator", - "args": { - "device_name": "LocalSimulator" - }, - "module": "modules.devices.braket.LocalSimulator", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", - "class": "SV1", - "args": { - "device_name": "SV1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" - }, - "module": "modules.devices.braket.SV1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", - "class": "TN1", - "args": { - "device_name": "TN1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" - }, - "module": "modules.devices.braket.TN1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", - "class": "Ionq", - "args": { - "device_name": "ionQ", - "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" - }, - "module": "modules.devices.braket.Ionq", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", - "class": "Rigetti", - "args": { - "device_name": "Rigetti Aspen-9", - "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" - }, - "module": "modules.devices.braket.Rigetti", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - } - ] - }, - { - "name": "PennylaneQAOA", - "class": "PennylaneQAOA", - "args": {}, - "module": "modules.solvers.PennylaneQAOA", - "requirements": [ - { - "name": "pennylane", - "version": "0.37.0" - }, - { - "name": "pennylane-lightning", - "version": "0.38.0" - }, - { - "name": "amazon-braket-pennylane-plugin", - "version": "1.30.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", - "class": "SV1", - "args": { - "device_name": "SV1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" - }, - "module": "modules.devices.braket.SV1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", - "class": "TN1", - "args": { - "device_name": "TN1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" - }, - "module": "modules.devices.braket.TN1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", - "class": "Ionq", - "args": { - "device_name": "ionq", - "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" - }, - "module": "modules.devices.braket.Ionq", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", - "class": "Rigetti", - "args": { - "device_name": "Rigetti", - "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" - }, - "module": "modules.devices.braket.Rigetti", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy", - "class": "OQC", - "args": { - "device_name": "OQC", - "arn": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" - }, - "module": "modules.devices.braket.OQC", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "braket.local.qubit", - "class": "HelperClass", - "args": { - "device_name": "braket.local.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "default.qubit", - "class": "HelperClass", - "args": { - "device_name": "default.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "default.qubit.autograd", - "class": "HelperClass", - "args": { - "device_name": "default.qubit.autograd" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "qulacs.simulator", - "class": "HelperClass", - "args": { - "device_name": "qulacs.simulator" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "lightning.gpu", - "class": "HelperClass", - "args": { - "device_name": "lightning.gpu" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "lightning.qubit", - "class": "HelperClass", - "args": { - "device_name": "lightning.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - } - ] - } - ] - } - ], - "requirements": [ - { - "name": "nnf", - "version": "0.4.1" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ] - }, - { - "name": "TSP", - "class": "TSP", - "module": "modules.applications.optimization.TSP.TSP", - "submodules": [ - { - "name": "Ising", - "class": "Ising", - "args": {}, - "module": "modules.applications.optimization.TSP.mappings.ISING", - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - }, - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "dimod", - "version": "0.12.17" - }, - { - "name": "more-itertools", - "version": "10.5.0" - }, - { - "name": "qiskit-optimization", - "version": "0.6.1" - }, - { - "name": "pyqubo", - "version": "1.4.0" - }, - { - "name": "networkx", - "version": "3.2.1" - }, - { - "name": "dwave_networkx", - "version": "0.8.15" - } - ], - "submodules": [ - { - "name": "QAOA", - "class": "QAOA", - "args": {}, - "module": "modules.solvers.QAOA", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "scipy", - "version": "1.12.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "LocalSimulator", - "class": "LocalSimulator", - "args": { - "device_name": "LocalSimulator" - }, - "module": "modules.devices.braket.LocalSimulator", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", - "class": "SV1", - "args": { - "device_name": "SV1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" - }, - "module": "modules.devices.braket.SV1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", - "class": "TN1", - "args": { - "device_name": "TN1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" - }, - "module": "modules.devices.braket.TN1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", - "class": "Ionq", - "args": { - "device_name": "ionQ", - "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" - }, - "module": "modules.devices.braket.Ionq", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", - "class": "Rigetti", - "args": { - "device_name": "Rigetti Aspen-9", - "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" - }, - "module": "modules.devices.braket.Rigetti", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - } - ] - }, - { - "name": "PennylaneQAOA", - "class": "PennylaneQAOA", - "args": {}, - "module": "modules.solvers.PennylaneQAOA", - "requirements": [ - { - "name": "pennylane", - "version": "0.37.0" - }, - { - "name": "pennylane-lightning", - "version": "0.38.0" - }, - { - "name": "amazon-braket-pennylane-plugin", - "version": "1.30.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", - "class": "SV1", - "args": { - "device_name": "SV1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" - }, - "module": "modules.devices.braket.SV1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", - "class": "TN1", - "args": { - "device_name": "TN1", - "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" - }, - "module": "modules.devices.braket.TN1", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", - "class": "Ionq", - "args": { - "device_name": "ionq", - "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" - }, - "module": "modules.devices.braket.Ionq", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", - "class": "Rigetti", - "args": { - "device_name": "Rigetti", - "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" - }, - "module": "modules.devices.braket.Rigetti", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy", - "class": "OQC", - "args": { - "device_name": "OQC", - "arn": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" - }, - "module": "modules.devices.braket.OQC", - "requirements": [ - { - "name": "amazon-braket-sdk", - "version": "1.87.0" - }, - { - "name": "botocore", - "version": "1.35.20" - }, - { - "name": "boto3", - "version": "1.35.20" - } - ], - "submodules": [] - }, - { - "name": "braket.local.qubit", - "class": "HelperClass", - "args": { - "device_name": "braket.local.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "default.qubit", - "class": "HelperClass", - "args": { - "device_name": "default.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "default.qubit.autograd", - "class": "HelperClass", - "args": { - "device_name": "default.qubit.autograd" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "qulacs.simulator", - "class": "HelperClass", - "args": { - "device_name": "qulacs.simulator" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "lightning.gpu", - "class": "HelperClass", - "args": { - "device_name": "lightning.gpu" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "lightning.qubit", - "class": "HelperClass", - "args": { - "device_name": "lightning.qubit" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - } - ] - }, - { - "name": "QiskitQAOA", - "class": "QiskitQAOA", - "args": {}, - "module": "modules.solvers.QiskitQAOA", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "qiskit-optimization", - "version": "0.6.1" - }, - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "qiskit-algorithms", - "version": "0.3.0" - } - ], - "submodules": [ - { - "name": "qasm_simulator", - "class": "HelperClass", - "args": { - "device_name": "qasm_simulator" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - }, - { - "name": "qasm_simulator_gpu", - "class": "HelperClass", - "args": { - "device_name": "qasm_simulator_gpu" - }, - "module": "modules.devices.HelperClass", - "requirements": [], - "submodules": [] - } - ] - } - ] - }, - { - "name": "QUBO", - "class": "QUBO", - "args": {}, - "module": "modules.applications.optimization.TSP.mappings.QUBO", - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - }, - { - "name": "dwave_networkx", - "version": "0.8.15" - } - ], - "submodules": [ - { - "name": "Annealer", - "class": "Annealer", - "args": {}, - "module": "modules.solvers.Annealer", - "requirements": [], - "submodules": [ - { - "name": "Simulated Annealer", - "class": "SimulatedAnnealingSampler", - "args": {}, - "module": "modules.devices.SimulatedAnnealingSampler", - "requirements": [ - { - "name": "dwave-samplers", - "version": "1.3.0" - } - ], - "submodules": [] - } - ] - } - ] - }, - { - "name": "GreedyClassicalTSP", - "class": "GreedyClassicalTSP", - "args": {}, - "module": "modules.solvers.GreedyClassicalTSP", - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - } - ], - "submodules": [ - { - "name": "Local", - "class": "Local", - "args": {}, - "module": "modules.devices.Local", - "requirements": [], - "submodules": [] - } - ] - }, - { - "name": "ReverseGreedyClassicalTSP", - "class": "ReverseGreedyClassicalTSP", - "args": {}, - "module": "modules.solvers.ReverseGreedyClassicalTSP", - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - } - ], - "submodules": [ - { - "name": "Local", - "class": "Local", - "args": {}, - "module": "modules.devices.Local", - "requirements": [], - "submodules": [] - } - ] - }, - { - "name": "RandomTSP", - "class": "RandomTSP", - "args": {}, - "module": "modules.solvers.RandomClassicalTSP", - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - } - ], - "submodules": [ - { - "name": "Local", - "class": "Local", - "args": {}, - "module": "modules.devices.Local", - "requirements": [], - "submodules": [] - } - ] - } - ], - "requirements": [ - { - "name": "networkx", - "version": "3.2.1" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ] - }, - { - "name": "ACL", - "class": "ACL", - "module": "modules.applications.optimization.ACL.ACL", - "submodules": [ - { - "name": "MIPsolverACL", - "class": "MIPaclp", - "args": {}, - "module": "modules.solvers.MIPsolverACL", - "requirements": [ - { - "name": "pulp", - "version": "2.9.0" - } - ], - "submodules": [ - { - "name": "Local", - "class": "Local", - "args": {}, - "module": "modules.devices.Local", - "requirements": [], - "submodules": [] - } - ] - }, - { - "name": "QUBO", - "class": "Qubo", - "args": {}, - "module": "modules.applications.optimization.ACL.mappings.QUBO", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "qiskit-optimization", - "version": "0.6.1" - } - ], - "submodules": [ - { - "name": "Annealer", - "class": "Annealer", - "args": {}, - "module": "modules.solvers.Annealer", - "requirements": [], - "submodules": [ - { - "name": "Simulated Annealer", - "class": "SimulatedAnnealingSampler", - "args": {}, - "module": "modules.devices.SimulatedAnnealingSampler", - "requirements": [ - { - "name": "dwave-samplers", - "version": "1.3.0" - } - ], - "submodules": [] - } - ] - } - ] - } - ], - "requirements": [ - { - "name": "pulp", - "version": "2.9.0" - }, - { - "name": "pandas", - "version": "2.2.2" - }, - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "openpyxl", - "version": "3.1.5" - } - ] - }, - { - "name": "MIS", - "class": "MIS", - "module": "modules.applications.optimization.MIS.MIS", - "submodules": [ - { - "name": "QIRO", - "class": "QIRO", - "args": {}, - "module": "modules.applications.optimization.MIS.mappings.QIRO", - "requirements": [ - { - "name": "qrisp", - "version": "0.5.2" - } - ], - "submodules": [ - { - "name": "QrispQIRO", - "class": "QIROSolver", - "args": {}, - "module": "modules.solvers.QrispQIRO", - "requirements": [ - { - "name": "qrisp", - "version": "0.5.2" - } - ], - "submodules": [ - { - "name": "qrisp_simulator", - "class": "QrispSimulator", - "args": {}, - "module": "modules.devices.qrisp_simulator.QrispSimulator", - "requirements": [ - { - "name": "qrisp", - "version": "0.5.2" - } - ], - "submodules": [] - } - ] - } - ] - }, - { - "name": "NeutralAtom", - "class": "NeutralAtom", - "args": {}, - "module": "modules.applications.optimization.MIS.mappings.NeutralAtom", - "requirements": [ - { - "name": "pulser", - "version": "0.19.0" - } - ], - "submodules": [ - { - "name": "NeutralAtomMIS", - "class": "NeutralAtomMIS", - "args": {}, - "module": "modules.solvers.NeutralAtomMIS", - "requirements": [ - { - "name": "pulser", - "version": "0.19.0" - } - ], - "submodules": [ - { - "name": "MockNeutralAtomDevice", - "class": "MockNeutralAtomDevice", - "args": {}, - "module": "modules.devices.pulser.MockNeutralAtomDevice", - "requirements": [ - { - "name": "pulser", - "version": "0.19.0" - } - ], - "submodules": [] - } - ] - } - ] - } - ], - "requirements": [] - }, - { - "name": "SCP", - "class": "SCP", - "module": "modules.applications.optimization.SCP.SCP", - "submodules": [ - { - "name": "qubovertQUBO", - "class": "QubovertQUBO", - "args": {}, - "module": "modules.applications.optimization.SCP.mappings.qubovertQUBO", - "requirements": [ - { - "name": "qubovert", - "version": "1.2.5" - } - ], - "submodules": [ - { - "name": "Annealer", - "class": "Annealer", - "args": {}, - "module": "modules.solvers.Annealer", - "requirements": [], - "submodules": [ - { - "name": "Simulated Annealer", - "class": "SimulatedAnnealingSampler", - "args": {}, - "module": "modules.devices.SimulatedAnnealingSampler", - "requirements": [ - { - "name": "dwave-samplers", - "version": "1.3.0" - } - ], - "submodules": [] - } - ] - } - ] - } - ], - "requirements": [] - }, - { - "name": "GenerativeModeling", - "class": "GenerativeModeling", - "module": "modules.applications.qml.generative_modeling.GenerativeModeling", - "submodules": [ - { - "name": "Continuous Data", - "class": "ContinuousData", - "args": {}, - "module": "modules.applications.qml.generative_modeling.data.data_handler.ContinuousData", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "PIT", - "class": "PIT", - "args": {}, - "module": "modules.applications.qml.generative_modeling.transformations.PIT", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "pandas", - "version": "2.2.2" - } - ], - "submodules": [ - { - "name": "CircuitCopula", - "class": "CircuitCopula", - "args": {}, - "module": "modules.applications.qml.generative_modeling.circuits.CircuitCopula", - "requirements": [ - { - "name": "scipy", - "version": "1.12.0" - } - ], - "submodules": [ - { - "name": "LibraryQiskit", - "class": "LibraryQiskit", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.LibraryQiskit", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "QGAN", - "class": "QGAN", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QGAN", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "torch", - "version": "2.2.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "LibraryPennylane", - "class": "LibraryPennylane", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.LibraryPennylane", - "requirements": [ - { - "name": "pennylane", - "version": "0.37.0" - }, - { - "name": "pennylane-lightning", - "version": "0.38.0" - }, - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "jax", - "version": "0.4.30" - }, - { - "name": "jaxlib", - "version": "0.4.30" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "QGAN", - "class": "QGAN", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QGAN", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "torch", - "version": "2.2.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "CustomQiskitNoisyBackend", - "class": "CustomQiskitNoisyBackend", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "qiskit_aer", - "version": "0.15.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "PresetQiskitNoisyBackend", - "class": "PresetQiskitNoisyBackend", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "qiskit_ibm_runtime", - "version": "0.29.0" - }, - { - "name": "qiskit_aer", - "version": "0.15.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - } - ] - } - ] - }, - { - "name": "MinMax", - "class": "MinMax", - "args": {}, - "module": "modules.applications.qml.generative_modeling.transformations.MinMax", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "CircuitStandard", - "class": "CircuitStandard", - "args": {}, - "module": "modules.applications.qml.generative_modeling.circuits.CircuitStandard", - "requirements": [], - "submodules": [ - { - "name": "LibraryQiskit", - "class": "LibraryQiskit", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.LibraryQiskit", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "QGAN", - "class": "QGAN", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QGAN", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "torch", - "version": "2.2.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "LibraryPennylane", - "class": "LibraryPennylane", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.LibraryPennylane", - "requirements": [ - { - "name": "pennylane", - "version": "0.37.0" - }, - { - "name": "pennylane-lightning", - "version": "0.38.0" - }, - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "jax", - "version": "0.4.30" - }, - { - "name": "jaxlib", - "version": "0.4.30" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "QGAN", - "class": "QGAN", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QGAN", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "torch", - "version": "2.2.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "CustomQiskitNoisyBackend", - "class": "CustomQiskitNoisyBackend", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "qiskit_aer", - "version": "0.15.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "PresetQiskitNoisyBackend", - "class": "PresetQiskitNoisyBackend", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "qiskit_ibm_runtime", - "version": "0.29.0" - }, - { - "name": "qiskit_aer", - "version": "0.15.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - } - ] - }, - { - "name": "CircuitCardinality", - "class": "CircuitCardinality", - "args": {}, - "module": "modules.applications.qml.generative_modeling.circuits.CircuitCardinality", - "requirements": [], - "submodules": [ - { - "name": "LibraryQiskit", - "class": "LibraryQiskit", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.LibraryQiskit", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "QGAN", - "class": "QGAN", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QGAN", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "torch", - "version": "2.2.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "LibraryPennylane", - "class": "LibraryPennylane", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.LibraryPennylane", - "requirements": [ - { - "name": "pennylane", - "version": "0.37.0" - }, - { - "name": "pennylane-lightning", - "version": "0.38.0" - }, - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "jax", - "version": "0.4.30" - }, - { - "name": "jaxlib", - "version": "0.4.30" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "QGAN", - "class": "QGAN", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QGAN", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "torch", - "version": "2.2.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "CustomQiskitNoisyBackend", - "class": "CustomQiskitNoisyBackend", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "qiskit_aer", - "version": "0.15.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "PresetQiskitNoisyBackend", - "class": "PresetQiskitNoisyBackend", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "qiskit_ibm_runtime", - "version": "0.29.0" - }, - { - "name": "qiskit_aer", - "version": "0.15.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - } - ] - } - ] - } - ] - }, - { - "name": "Discrete Data", - "class": "DiscreteData", - "args": {}, - "module": "modules.applications.qml.generative_modeling.data.data_handler.DiscreteData", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "CircuitCardinality", - "class": "CircuitCardinality", - "args": {}, - "module": "modules.applications.qml.generative_modeling.circuits.CircuitCardinality", - "requirements": [], - "submodules": [ - { - "name": "LibraryQiskit", - "class": "LibraryQiskit", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.LibraryQiskit", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "QGAN", - "class": "QGAN", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QGAN", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "torch", - "version": "2.2.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "LibraryPennylane", - "class": "LibraryPennylane", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.LibraryPennylane", - "requirements": [ - { - "name": "pennylane", - "version": "0.37.0" - }, - { - "name": "pennylane-lightning", - "version": "0.38.0" - }, - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "jax", - "version": "0.4.30" - }, - { - "name": "jaxlib", - "version": "0.4.30" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "QGAN", - "class": "QGAN", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QGAN", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "torch", - "version": "2.2.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "CustomQiskitNoisyBackend", - "class": "CustomQiskitNoisyBackend", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "qiskit_aer", - "version": "0.15.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - }, - { - "name": "PresetQiskitNoisyBackend", - "class": "PresetQiskitNoisyBackend", - "args": {}, - "module": "modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend", - "requirements": [ - { - "name": "qiskit", - "version": "1.1.0" - }, - { - "name": "qiskit_ibm_runtime", - "version": "0.29.0" - }, - { - "name": "qiskit_aer", - "version": "0.15.0" - }, - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [ - { - "name": "QCBM", - "class": "QCBM", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.QCBM", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - }, - { - "name": "cma", - "version": "4.0.0" - }, - { - "name": "matplotlib", - "version": "3.7.5" - }, - { - "name": "tensorboard", - "version": "2.17.0" - }, - { - "name": "tensorboardX", - "version": "2.6.2.2" - } - ], - "submodules": [] - }, - { - "name": "Inference", - "class": "Inference", - "args": {}, - "module": "modules.applications.qml.generative_modeling.training.Inference", - "requirements": [ - { - "name": "numpy", - "version": "1.26.4" - } - ], - "submodules": [] - } - ] - } - ] - } - ] - } - ], - "requirements": [] - } - ] +{ + "build_number": 16, + "build_date": "03-12-2024 10:33:07", + "git_revision_number": "5dd793e3a63cae9acd48fc083569f9ba20615e4c", + "modules": [ + { + "name": "PVC", + "class": "PVC", + "module": "modules.applications.optimization.PVC.PVC", + "submodules": [ + { + "name": "Ising", + "class": "Ising", + "args": {}, + "module": "modules.applications.optimization.PVC.mappings.ISING", + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + }, + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "dimod", + "version": "0.12.17" + }, + { + "name": "networkx", + "version": "3.2.1" + } + ], + "submodules": [ + { + "name": "QAOA", + "class": "QAOA", + "args": {}, + "module": "modules.solvers.QAOA", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "scipy", + "version": "1.12.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "LocalSimulator", + "class": "LocalSimulator", + "args": { + "device_name": "LocalSimulator" + }, + "module": "modules.devices.braket.LocalSimulator", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", + "class": "SV1", + "args": { + "device_name": "SV1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" + }, + "module": "modules.devices.braket.SV1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", + "class": "TN1", + "args": { + "device_name": "TN1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" + }, + "module": "modules.devices.braket.TN1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", + "class": "Ionq", + "args": { + "device_name": "ionQ", + "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" + }, + "module": "modules.devices.braket.Ionq", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", + "class": "Rigetti", + "args": { + "device_name": "Rigetti Aspen-9", + "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" + }, + "module": "modules.devices.braket.Rigetti", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + } + ] + }, + { + "name": "PennylaneQAOA", + "class": "PennylaneQAOA", + "args": {}, + "module": "modules.solvers.PennylaneQAOA", + "requirements": [ + { + "name": "pennylane", + "version": "0.37.0" + }, + { + "name": "pennylane-lightning", + "version": "0.38.0" + }, + { + "name": "amazon-braket-pennylane-plugin", + "version": "1.30.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", + "class": "SV1", + "args": { + "device_name": "SV1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" + }, + "module": "modules.devices.braket.SV1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", + "class": "TN1", + "args": { + "device_name": "TN1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" + }, + "module": "modules.devices.braket.TN1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", + "class": "Ionq", + "args": { + "device_name": "ionq", + "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" + }, + "module": "modules.devices.braket.Ionq", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", + "class": "Rigetti", + "args": { + "device_name": "Rigetti", + "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" + }, + "module": "modules.devices.braket.Rigetti", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy", + "class": "OQC", + "args": { + "device_name": "OQC", + "arn": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" + }, + "module": "modules.devices.braket.OQC", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "braket.local.qubit", + "class": "HelperClass", + "args": { + "device_name": "braket.local.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "default.qubit", + "class": "HelperClass", + "args": { + "device_name": "default.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "default.qubit.autograd", + "class": "HelperClass", + "args": { + "device_name": "default.qubit.autograd" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "qulacs.simulator", + "class": "HelperClass", + "args": { + "device_name": "qulacs.simulator" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "lightning.gpu", + "class": "HelperClass", + "args": { + "device_name": "lightning.gpu" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "lightning.qubit", + "class": "HelperClass", + "args": { + "device_name": "lightning.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + } + ] + } + ] + }, + { + "name": "QUBO", + "class": "QUBO", + "args": {}, + "module": "modules.applications.optimization.PVC.mappings.QUBO", + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + } + ], + "submodules": [ + { + "name": "Annealer", + "class": "Annealer", + "args": {}, + "module": "modules.solvers.Annealer", + "requirements": [], + "submodules": [ + { + "name": "Simulated Annealer", + "class": "SimulatedAnnealingSampler", + "args": {}, + "module": "modules.devices.SimulatedAnnealingSampler", + "requirements": [ + { + "name": "dwave-samplers", + "version": "1.3.0" + } + ], + "submodules": [] + } + ] + } + ] + }, + { + "name": "GreedyClassicalPVC", + "class": "GreedyClassicalPVC", + "args": {}, + "module": "modules.solvers.GreedyClassicalPVC", + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + } + ], + "submodules": [ + { + "name": "Local", + "class": "Local", + "args": {}, + "module": "modules.devices.Local", + "requirements": [], + "submodules": [] + } + ] + }, + { + "name": "ReverseGreedyClassicalPVC", + "class": "ReverseGreedyClassicalPVC", + "args": {}, + "module": "modules.solvers.ReverseGreedyClassicalPVC", + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + } + ], + "submodules": [ + { + "name": "Local", + "class": "Local", + "args": {}, + "module": "modules.devices.Local", + "requirements": [], + "submodules": [] + } + ] + }, + { + "name": "RandomPVC", + "class": "RandomPVC", + "args": {}, + "module": "modules.solvers.RandomClassicalPVC", + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + } + ], + "submodules": [ + { + "name": "Local", + "class": "Local", + "args": {}, + "module": "modules.devices.Local", + "requirements": [], + "submodules": [] + } + ] + } + ], + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ] + }, + { + "name": "SAT", + "class": "SAT", + "module": "modules.applications.optimization.SAT.SAT", + "submodules": [ + { + "name": "QubovertQUBO", + "class": "QubovertQUBO", + "args": {}, + "module": "modules.applications.optimization.SAT.mappings.QubovertQUBO", + "requirements": [ + { + "name": "nnf", + "version": "0.4.1" + }, + { + "name": "qubovert", + "version": "1.2.5" + } + ], + "submodules": [ + { + "name": "Annealer", + "class": "Annealer", + "args": {}, + "module": "modules.solvers.Annealer", + "requirements": [], + "submodules": [ + { + "name": "Simulated Annealer", + "class": "SimulatedAnnealingSampler", + "args": {}, + "module": "modules.devices.SimulatedAnnealingSampler", + "requirements": [ + { + "name": "dwave-samplers", + "version": "1.3.0" + } + ], + "submodules": [] + } + ] + } + ] + }, + { + "name": "Direct", + "class": "Direct", + "args": {}, + "module": "modules.applications.optimization.SAT.mappings.Direct", + "requirements": [ + { + "name": "nnf", + "version": "0.4.1" + }, + { + "name": "python-sat", + "version": "1.8.dev13" + } + ], + "submodules": [ + { + "name": "ClassicalSAT", + "class": "ClassicalSAT", + "args": {}, + "module": "modules.solvers.ClassicalSAT", + "requirements": [ + { + "name": "python-sat", + "version": "1.8.dev13" + } + ], + "submodules": [ + { + "name": "Local", + "class": "Local", + "args": {}, + "module": "modules.devices.Local", + "requirements": [], + "submodules": [] + } + ] + }, + { + "name": "RandomSAT", + "class": "RandomSAT", + "args": {}, + "module": "modules.solvers.RandomClassicalSAT", + "requirements": [ + { + "name": "python-sat", + "version": "1.8.dev13" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "Local", + "class": "Local", + "args": {}, + "module": "modules.devices.Local", + "requirements": [], + "submodules": [] + } + ] + } + ] + }, + { + "name": "ChoiQUBO", + "class": "ChoiQUBO", + "args": {}, + "module": "modules.applications.optimization.SAT.mappings.ChoiQUBO", + "requirements": [ + { + "name": "nnf", + "version": "0.4.1" + } + ], + "submodules": [ + { + "name": "Annealer", + "class": "Annealer", + "args": {}, + "module": "modules.solvers.Annealer", + "requirements": [], + "submodules": [ + { + "name": "Simulated Annealer", + "class": "SimulatedAnnealingSampler", + "args": {}, + "module": "modules.devices.SimulatedAnnealingSampler", + "requirements": [ + { + "name": "dwave-samplers", + "version": "1.3.0" + } + ], + "submodules": [] + } + ] + } + ] + }, + { + "name": "DinneenQUBO", + "class": "DinneenQUBO", + "args": {}, + "module": "modules.applications.optimization.SAT.mappings.DinneenQUBO", + "requirements": [ + { + "name": "nnf", + "version": "0.4.1" + } + ], + "submodules": [ + { + "name": "Annealer", + "class": "Annealer", + "args": {}, + "module": "modules.solvers.Annealer", + "requirements": [], + "submodules": [ + { + "name": "Simulated Annealer", + "class": "SimulatedAnnealingSampler", + "args": {}, + "module": "modules.devices.SimulatedAnnealingSampler", + "requirements": [ + { + "name": "dwave-samplers", + "version": "1.3.0" + } + ], + "submodules": [] + } + ] + } + ] + }, + { + "name": "ChoiIsing", + "class": "ChoiIsing", + "args": {}, + "module": "modules.applications.optimization.SAT.mappings.ChoiISING", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "dimod", + "version": "0.12.17" + }, + { + "name": "nnf", + "version": "0.4.1" + } + ], + "submodules": [ + { + "name": "QAOA", + "class": "QAOA", + "args": {}, + "module": "modules.solvers.QAOA", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "scipy", + "version": "1.12.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "LocalSimulator", + "class": "LocalSimulator", + "args": { + "device_name": "LocalSimulator" + }, + "module": "modules.devices.braket.LocalSimulator", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", + "class": "SV1", + "args": { + "device_name": "SV1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" + }, + "module": "modules.devices.braket.SV1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", + "class": "TN1", + "args": { + "device_name": "TN1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" + }, + "module": "modules.devices.braket.TN1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", + "class": "Ionq", + "args": { + "device_name": "ionQ", + "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" + }, + "module": "modules.devices.braket.Ionq", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", + "class": "Rigetti", + "args": { + "device_name": "Rigetti Aspen-9", + "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" + }, + "module": "modules.devices.braket.Rigetti", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + } + ] + }, + { + "name": "PennylaneQAOA", + "class": "PennylaneQAOA", + "args": {}, + "module": "modules.solvers.PennylaneQAOA", + "requirements": [ + { + "name": "pennylane", + "version": "0.37.0" + }, + { + "name": "pennylane-lightning", + "version": "0.38.0" + }, + { + "name": "amazon-braket-pennylane-plugin", + "version": "1.30.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", + "class": "SV1", + "args": { + "device_name": "SV1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" + }, + "module": "modules.devices.braket.SV1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", + "class": "TN1", + "args": { + "device_name": "TN1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" + }, + "module": "modules.devices.braket.TN1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", + "class": "Ionq", + "args": { + "device_name": "ionq", + "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" + }, + "module": "modules.devices.braket.Ionq", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", + "class": "Rigetti", + "args": { + "device_name": "Rigetti", + "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" + }, + "module": "modules.devices.braket.Rigetti", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy", + "class": "OQC", + "args": { + "device_name": "OQC", + "arn": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" + }, + "module": "modules.devices.braket.OQC", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "braket.local.qubit", + "class": "HelperClass", + "args": { + "device_name": "braket.local.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "default.qubit", + "class": "HelperClass", + "args": { + "device_name": "default.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "default.qubit.autograd", + "class": "HelperClass", + "args": { + "device_name": "default.qubit.autograd" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "qulacs.simulator", + "class": "HelperClass", + "args": { + "device_name": "qulacs.simulator" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "lightning.gpu", + "class": "HelperClass", + "args": { + "device_name": "lightning.gpu" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "lightning.qubit", + "class": "HelperClass", + "args": { + "device_name": "lightning.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + } + ] + } + ] + }, + { + "name": "DinneenIsing", + "class": "DinneenIsing", + "args": {}, + "module": "modules.applications.optimization.SAT.mappings.DinneenISING", + "requirements": [ + { + "name": "nnf", + "version": "0.4.1" + }, + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "dimod", + "version": "0.12.17" + }, + { + "name": "nnf", + "version": "0.4.1" + } + ], + "submodules": [ + { + "name": "QAOA", + "class": "QAOA", + "args": {}, + "module": "modules.solvers.QAOA", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "scipy", + "version": "1.12.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "LocalSimulator", + "class": "LocalSimulator", + "args": { + "device_name": "LocalSimulator" + }, + "module": "modules.devices.braket.LocalSimulator", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", + "class": "SV1", + "args": { + "device_name": "SV1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" + }, + "module": "modules.devices.braket.SV1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", + "class": "TN1", + "args": { + "device_name": "TN1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" + }, + "module": "modules.devices.braket.TN1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", + "class": "Ionq", + "args": { + "device_name": "ionQ", + "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" + }, + "module": "modules.devices.braket.Ionq", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", + "class": "Rigetti", + "args": { + "device_name": "Rigetti Aspen-9", + "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" + }, + "module": "modules.devices.braket.Rigetti", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + } + ] + }, + { + "name": "PennylaneQAOA", + "class": "PennylaneQAOA", + "args": {}, + "module": "modules.solvers.PennylaneQAOA", + "requirements": [ + { + "name": "pennylane", + "version": "0.37.0" + }, + { + "name": "pennylane-lightning", + "version": "0.38.0" + }, + { + "name": "amazon-braket-pennylane-plugin", + "version": "1.30.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", + "class": "SV1", + "args": { + "device_name": "SV1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" + }, + "module": "modules.devices.braket.SV1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", + "class": "TN1", + "args": { + "device_name": "TN1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" + }, + "module": "modules.devices.braket.TN1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", + "class": "Ionq", + "args": { + "device_name": "ionq", + "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" + }, + "module": "modules.devices.braket.Ionq", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", + "class": "Rigetti", + "args": { + "device_name": "Rigetti", + "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" + }, + "module": "modules.devices.braket.Rigetti", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy", + "class": "OQC", + "args": { + "device_name": "OQC", + "arn": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" + }, + "module": "modules.devices.braket.OQC", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "braket.local.qubit", + "class": "HelperClass", + "args": { + "device_name": "braket.local.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "default.qubit", + "class": "HelperClass", + "args": { + "device_name": "default.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "default.qubit.autograd", + "class": "HelperClass", + "args": { + "device_name": "default.qubit.autograd" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "qulacs.simulator", + "class": "HelperClass", + "args": { + "device_name": "qulacs.simulator" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "lightning.gpu", + "class": "HelperClass", + "args": { + "device_name": "lightning.gpu" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "lightning.qubit", + "class": "HelperClass", + "args": { + "device_name": "lightning.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + } + ] + } + ] + } + ], + "requirements": [ + { + "name": "nnf", + "version": "0.4.1" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ] + }, + { + "name": "TSP", + "class": "TSP", + "module": "modules.applications.optimization.TSP.TSP", + "submodules": [ + { + "name": "Ising", + "class": "Ising", + "args": {}, + "module": "modules.applications.optimization.TSP.mappings.ISING", + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + }, + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "dimod", + "version": "0.12.17" + }, + { + "name": "more-itertools", + "version": "10.5.0" + }, + { + "name": "qiskit-optimization", + "version": "0.6.1" + }, + { + "name": "pyqubo", + "version": "1.4.0" + }, + { + "name": "networkx", + "version": "3.2.1" + }, + { + "name": "dwave_networkx", + "version": "0.8.15" + } + ], + "submodules": [ + { + "name": "QAOA", + "class": "QAOA", + "args": {}, + "module": "modules.solvers.QAOA", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "scipy", + "version": "1.12.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "LocalSimulator", + "class": "LocalSimulator", + "args": { + "device_name": "LocalSimulator" + }, + "module": "modules.devices.braket.LocalSimulator", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", + "class": "SV1", + "args": { + "device_name": "SV1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" + }, + "module": "modules.devices.braket.SV1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", + "class": "TN1", + "args": { + "device_name": "TN1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" + }, + "module": "modules.devices.braket.TN1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", + "class": "Ionq", + "args": { + "device_name": "ionQ", + "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" + }, + "module": "modules.devices.braket.Ionq", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", + "class": "Rigetti", + "args": { + "device_name": "Rigetti Aspen-9", + "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" + }, + "module": "modules.devices.braket.Rigetti", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + } + ] + }, + { + "name": "PennylaneQAOA", + "class": "PennylaneQAOA", + "args": {}, + "module": "modules.solvers.PennylaneQAOA", + "requirements": [ + { + "name": "pennylane", + "version": "0.37.0" + }, + { + "name": "pennylane-lightning", + "version": "0.38.0" + }, + { + "name": "amazon-braket-pennylane-plugin", + "version": "1.30.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/sv1", + "class": "SV1", + "args": { + "device_name": "SV1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/sv1" + }, + "module": "modules.devices.braket.SV1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:::device/quantum-simulator/amazon/tn1", + "class": "TN1", + "args": { + "device_name": "TN1", + "arn": "arn:aws:braket:::device/quantum-simulator/amazon/tn1" + }, + "module": "modules.devices.braket.TN1", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony", + "class": "Ionq", + "args": { + "device_name": "ionq", + "arn": "arn:aws:braket:us-east-1::device/qpu/ionq/Harmony" + }, + "module": "modules.devices.braket.Ionq", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3", + "class": "Rigetti", + "args": { + "device_name": "Rigetti", + "arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-3" + }, + "module": "modules.devices.braket.Rigetti", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy", + "class": "OQC", + "args": { + "device_name": "OQC", + "arn": "arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy" + }, + "module": "modules.devices.braket.OQC", + "requirements": [ + { + "name": "amazon-braket-sdk", + "version": "1.87.0" + }, + { + "name": "botocore", + "version": "1.35.20" + }, + { + "name": "boto3", + "version": "1.35.20" + } + ], + "submodules": [] + }, + { + "name": "braket.local.qubit", + "class": "HelperClass", + "args": { + "device_name": "braket.local.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "default.qubit", + "class": "HelperClass", + "args": { + "device_name": "default.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "default.qubit.autograd", + "class": "HelperClass", + "args": { + "device_name": "default.qubit.autograd" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "qulacs.simulator", + "class": "HelperClass", + "args": { + "device_name": "qulacs.simulator" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "lightning.gpu", + "class": "HelperClass", + "args": { + "device_name": "lightning.gpu" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "lightning.qubit", + "class": "HelperClass", + "args": { + "device_name": "lightning.qubit" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + } + ] + }, + { + "name": "QiskitQAOA", + "class": "QiskitQAOA", + "args": {}, + "module": "modules.solvers.QiskitQAOA", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "qiskit-optimization", + "version": "0.6.1" + }, + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "qiskit-algorithms", + "version": "0.3.0" + } + ], + "submodules": [ + { + "name": "qasm_simulator", + "class": "HelperClass", + "args": { + "device_name": "qasm_simulator" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + }, + { + "name": "qasm_simulator_gpu", + "class": "HelperClass", + "args": { + "device_name": "qasm_simulator_gpu" + }, + "module": "modules.devices.HelperClass", + "requirements": [], + "submodules": [] + } + ] + } + ] + }, + { + "name": "QUBO", + "class": "QUBO", + "args": {}, + "module": "modules.applications.optimization.TSP.mappings.QUBO", + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + }, + { + "name": "dwave_networkx", + "version": "0.8.15" + } + ], + "submodules": [ + { + "name": "Annealer", + "class": "Annealer", + "args": {}, + "module": "modules.solvers.Annealer", + "requirements": [], + "submodules": [ + { + "name": "Simulated Annealer", + "class": "SimulatedAnnealingSampler", + "args": {}, + "module": "modules.devices.SimulatedAnnealingSampler", + "requirements": [ + { + "name": "dwave-samplers", + "version": "1.3.0" + } + ], + "submodules": [] + } + ] + } + ] + }, + { + "name": "GreedyClassicalTSP", + "class": "GreedyClassicalTSP", + "args": {}, + "module": "modules.solvers.GreedyClassicalTSP", + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + } + ], + "submodules": [ + { + "name": "Local", + "class": "Local", + "args": {}, + "module": "modules.devices.Local", + "requirements": [], + "submodules": [] + } + ] + }, + { + "name": "ReverseGreedyClassicalTSP", + "class": "ReverseGreedyClassicalTSP", + "args": {}, + "module": "modules.solvers.ReverseGreedyClassicalTSP", + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + } + ], + "submodules": [ + { + "name": "Local", + "class": "Local", + "args": {}, + "module": "modules.devices.Local", + "requirements": [], + "submodules": [] + } + ] + }, + { + "name": "RandomTSP", + "class": "RandomTSP", + "args": {}, + "module": "modules.solvers.RandomClassicalTSP", + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + } + ], + "submodules": [ + { + "name": "Local", + "class": "Local", + "args": {}, + "module": "modules.devices.Local", + "requirements": [], + "submodules": [] + } + ] + } + ], + "requirements": [ + { + "name": "networkx", + "version": "3.2.1" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ] + }, + { + "name": "ACL", + "class": "ACL", + "module": "modules.applications.optimization.ACL.ACL", + "submodules": [ + { + "name": "MIPsolverACL", + "class": "MIPaclp", + "args": {}, + "module": "modules.solvers.MIPsolverACL", + "requirements": [ + { + "name": "pulp", + "version": "2.9.0" + } + ], + "submodules": [ + { + "name": "Local", + "class": "Local", + "args": {}, + "module": "modules.devices.Local", + "requirements": [], + "submodules": [] + } + ] + }, + { + "name": "QUBO", + "class": "Qubo", + "args": {}, + "module": "modules.applications.optimization.ACL.mappings.QUBO", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "qiskit-optimization", + "version": "0.6.1" + } + ], + "submodules": [ + { + "name": "Annealer", + "class": "Annealer", + "args": {}, + "module": "modules.solvers.Annealer", + "requirements": [], + "submodules": [ + { + "name": "Simulated Annealer", + "class": "SimulatedAnnealingSampler", + "args": {}, + "module": "modules.devices.SimulatedAnnealingSampler", + "requirements": [ + { + "name": "dwave-samplers", + "version": "1.3.0" + } + ], + "submodules": [] + } + ] + } + ] + } + ], + "requirements": [ + { + "name": "pulp", + "version": "2.9.0" + }, + { + "name": "pandas", + "version": "2.2.2" + }, + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "openpyxl", + "version": "3.1.5" + } + ] + }, + { + "name": "MIS", + "class": "MIS", + "module": "modules.applications.optimization.MIS.MIS", + "submodules": [ + { + "name": "QIRO", + "class": "QIRO", + "args": {}, + "module": "modules.applications.optimization.MIS.mappings.QIRO", + "requirements": [ + { + "name": "qrisp", + "version": "0.5.2" + } + ], + "submodules": [ + { + "name": "QrispQIRO", + "class": "QIROSolver", + "args": {}, + "module": "modules.solvers.QrispQIRO", + "requirements": [ + { + "name": "qrisp", + "version": "0.5.2" + } + ], + "submodules": [ + { + "name": "qrisp_simulator", + "class": "QrispSimulator", + "args": {}, + "module": "modules.devices.qrisp_simulator.QrispSimulator", + "requirements": [ + { + "name": "qrisp", + "version": "0.5.2" + } + ], + "submodules": [] + } + ] + } + ] + }, + { + "name": "NeutralAtom", + "class": "NeutralAtom", + "args": {}, + "module": "modules.applications.optimization.MIS.mappings.NeutralAtom", + "requirements": [ + { + "name": "pulser", + "version": "0.19.0" + } + ], + "submodules": [ + { + "name": "NeutralAtomMIS", + "class": "NeutralAtomMIS", + "args": {}, + "module": "modules.solvers.NeutralAtomMIS", + "requirements": [ + { + "name": "pulser", + "version": "0.19.0" + } + ], + "submodules": [ + { + "name": "MockNeutralAtomDevice", + "class": "MockNeutralAtomDevice", + "args": {}, + "module": "modules.devices.pulser.MockNeutralAtomDevice", + "requirements": [ + { + "name": "pulser", + "version": "0.19.0" + } + ], + "submodules": [] + } + ] + } + ] + } + ], + "requirements": [] + }, + { + "name": "SCP", + "class": "SCP", + "module": "modules.applications.optimization.SCP.SCP", + "submodules": [ + { + "name": "qubovertQUBO", + "class": "QubovertQUBO", + "args": {}, + "module": "modules.applications.optimization.SCP.mappings.qubovertQUBO", + "requirements": [ + { + "name": "qubovert", + "version": "1.2.5" + } + ], + "submodules": [ + { + "name": "Annealer", + "class": "Annealer", + "args": {}, + "module": "modules.solvers.Annealer", + "requirements": [], + "submodules": [ + { + "name": "Simulated Annealer", + "class": "SimulatedAnnealingSampler", + "args": {}, + "module": "modules.devices.SimulatedAnnealingSampler", + "requirements": [ + { + "name": "dwave-samplers", + "version": "1.3.0" + } + ], + "submodules": [] + } + ] + } + ] + } + ], + "requirements": [] + }, + { + "name": "GenerativeModeling", + "class": "GenerativeModeling", + "module": "modules.applications.qml.generative_modeling.GenerativeModeling", + "submodules": [ + { + "name": "Continuous Data", + "class": "ContinuousData", + "args": {}, + "module": "modules.applications.qml.generative_modeling.data.data_handler.ContinuousData", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "PIT", + "class": "PIT", + "args": {}, + "module": "modules.applications.qml.generative_modeling.transformations.PIT", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "pandas", + "version": "2.2.2" + } + ], + "submodules": [ + { + "name": "CircuitCopula", + "class": "CircuitCopula", + "args": {}, + "module": "modules.applications.qml.generative_modeling.circuits.CircuitCopula", + "requirements": [ + { + "name": "scipy", + "version": "1.12.0" + } + ], + "submodules": [ + { + "name": "LibraryQiskit", + "class": "LibraryQiskit", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.LibraryQiskit", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "QGAN", + "class": "QGAN", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QGAN", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "torch", + "version": "2.2.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "LibraryPennylane", + "class": "LibraryPennylane", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.LibraryPennylane", + "requirements": [ + { + "name": "pennylane", + "version": "0.37.0" + }, + { + "name": "pennylane-lightning", + "version": "0.38.0" + }, + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "jax", + "version": "0.4.30" + }, + { + "name": "jaxlib", + "version": "0.4.30" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "QGAN", + "class": "QGAN", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QGAN", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "torch", + "version": "2.2.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "CustomQiskitNoisyBackend", + "class": "CustomQiskitNoisyBackend", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "qiskit_aer", + "version": "0.15.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "PresetQiskitNoisyBackend", + "class": "PresetQiskitNoisyBackend", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "qiskit_ibm_runtime", + "version": "0.29.0" + }, + { + "name": "qiskit_aer", + "version": "0.15.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + } + ] + } + ] + }, + { + "name": "MinMax", + "class": "MinMax", + "args": {}, + "module": "modules.applications.qml.generative_modeling.transformations.MinMax", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "CircuitStandard", + "class": "CircuitStandard", + "args": {}, + "module": "modules.applications.qml.generative_modeling.circuits.CircuitStandard", + "requirements": [], + "submodules": [ + { + "name": "LibraryQiskit", + "class": "LibraryQiskit", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.LibraryQiskit", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "QGAN", + "class": "QGAN", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QGAN", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "torch", + "version": "2.2.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "LibraryPennylane", + "class": "LibraryPennylane", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.LibraryPennylane", + "requirements": [ + { + "name": "pennylane", + "version": "0.37.0" + }, + { + "name": "pennylane-lightning", + "version": "0.38.0" + }, + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "jax", + "version": "0.4.30" + }, + { + "name": "jaxlib", + "version": "0.4.30" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "QGAN", + "class": "QGAN", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QGAN", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "torch", + "version": "2.2.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "CustomQiskitNoisyBackend", + "class": "CustomQiskitNoisyBackend", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "qiskit_aer", + "version": "0.15.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "PresetQiskitNoisyBackend", + "class": "PresetQiskitNoisyBackend", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "qiskit_ibm_runtime", + "version": "0.29.0" + }, + { + "name": "qiskit_aer", + "version": "0.15.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + } + ] + }, + { + "name": "CircuitCardinality", + "class": "CircuitCardinality", + "args": {}, + "module": "modules.applications.qml.generative_modeling.circuits.CircuitCardinality", + "requirements": [], + "submodules": [ + { + "name": "LibraryQiskit", + "class": "LibraryQiskit", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.LibraryQiskit", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "QGAN", + "class": "QGAN", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QGAN", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "torch", + "version": "2.2.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "LibraryPennylane", + "class": "LibraryPennylane", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.LibraryPennylane", + "requirements": [ + { + "name": "pennylane", + "version": "0.37.0" + }, + { + "name": "pennylane-lightning", + "version": "0.38.0" + }, + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "jax", + "version": "0.4.30" + }, + { + "name": "jaxlib", + "version": "0.4.30" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "QGAN", + "class": "QGAN", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QGAN", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "torch", + "version": "2.2.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "CustomQiskitNoisyBackend", + "class": "CustomQiskitNoisyBackend", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "qiskit_aer", + "version": "0.15.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "PresetQiskitNoisyBackend", + "class": "PresetQiskitNoisyBackend", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "qiskit_ibm_runtime", + "version": "0.29.0" + }, + { + "name": "qiskit_aer", + "version": "0.15.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + } + ] + } + ] + } + ] + }, + { + "name": "Discrete Data", + "class": "DiscreteData", + "args": {}, + "module": "modules.applications.qml.generative_modeling.data.data_handler.DiscreteData", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "CircuitCardinality", + "class": "CircuitCardinality", + "args": {}, + "module": "modules.applications.qml.generative_modeling.circuits.CircuitCardinality", + "requirements": [], + "submodules": [ + { + "name": "LibraryQiskit", + "class": "LibraryQiskit", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.LibraryQiskit", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "QGAN", + "class": "QGAN", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QGAN", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "torch", + "version": "2.2.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "LibraryPennylane", + "class": "LibraryPennylane", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.LibraryPennylane", + "requirements": [ + { + "name": "pennylane", + "version": "0.37.0" + }, + { + "name": "pennylane-lightning", + "version": "0.38.0" + }, + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "jax", + "version": "0.4.30" + }, + { + "name": "jaxlib", + "version": "0.4.30" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "QGAN", + "class": "QGAN", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QGAN", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "torch", + "version": "2.2.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "CustomQiskitNoisyBackend", + "class": "CustomQiskitNoisyBackend", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "qiskit_aer", + "version": "0.15.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + }, + { + "name": "PresetQiskitNoisyBackend", + "class": "PresetQiskitNoisyBackend", + "args": {}, + "module": "modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend", + "requirements": [ + { + "name": "qiskit", + "version": "1.1.0" + }, + { + "name": "qiskit_ibm_runtime", + "version": "0.29.0" + }, + { + "name": "qiskit_aer", + "version": "0.15.0" + }, + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [ + { + "name": "QCBM", + "class": "QCBM", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.QCBM", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + }, + { + "name": "cma", + "version": "4.0.0" + }, + { + "name": "matplotlib", + "version": "3.7.5" + }, + { + "name": "tensorboard", + "version": "2.17.0" + }, + { + "name": "tensorboardX", + "version": "2.6.2.2" + } + ], + "submodules": [] + }, + { + "name": "Inference", + "class": "Inference", + "args": {}, + "module": "modules.applications.qml.generative_modeling.training.Inference", + "requirements": [ + { + "name": "numpy", + "version": "1.26.4" + } + ], + "submodules": [] + } + ] + } + ] + } + ] + } + ], + "requirements": [] + } + ] } \ No newline at end of file diff --git a/src/modules/applications/optimization/ACL/mappings/ISING.py b/src/modules/applications/optimization/ACL/mappings/ISING.py index ee4722a7..3a831f0d 100644 --- a/src/modules/applications/optimization/ACL/mappings/ISING.py +++ b/src/modules/applications/optimization/ACL/mappings/ISING.py @@ -144,7 +144,7 @@ def map(self, problem: dict, config: Config) -> tuple[dict, float]: j_matrix = np.zeros((qubit_op.num_qubits, qubit_op.num_qubits), dtype=complex) for pauli_op in qubit_op: - pauli_str, coeff = pauli_op.primitive.to_list()[0] + pauli_str, coeff = pauli_op.to_list()[0] index_pos_list = list(locate(pauli_str, lambda a: a == 'Z')) if len(index_pos_list) == 1: diff --git a/src/modules/applications/qml/generative_modeling/data/data_handler/ContinuousData.py b/src/modules/applications/qml/generative_modeling/data/data_handler/ContinuousData.py index e463b750..46aa51c5 100644 --- a/src/modules/applications/qml/generative_modeling/data/data_handler/ContinuousData.py +++ b/src/modules/applications/qml/generative_modeling/data/data_handler/ContinuousData.py @@ -165,4 +165,7 @@ def kl_divergence(self, target: np.ndarray, q: np.ndarray) -> float: :param q: Probability mass function generated by the quantum circuit :return: Kullback-Leibler divergence """ + if q.shape != target.shape: + q = np.resize(q, target.shape) + return np.sum(target * np.log(target / q)) diff --git a/src/modules/applications/qml/generative_modeling/training/QGAN.py b/src/modules/applications/qml/generative_modeling/training/QGAN.py index 7abbaa78..f06dcbe4 100644 --- a/src/modules/applications/qml/generative_modeling/training/QGAN.py +++ b/src/modules/applications/qml/generative_modeling/training/QGAN.py @@ -142,7 +142,7 @@ def get_parameter_options(self) -> dict: }, "learning_rate_generator": { "values": [0.1, 0.2], - "description": "What learnig rate do you want to set for the generator?" + "description": "What learning rate do you want to set for the generator?" }, "learning_rate_discriminator": { "values": [0.1, 0.05], diff --git a/src/modules/applications/qml/generative_modeling/transformations/PIT.py b/src/modules/applications/qml/generative_modeling/transformations/PIT.py index 41532995..3f47bb6a 100644 --- a/src/modules/applications/qml/generative_modeling/transformations/PIT.py +++ b/src/modules/applications/qml/generative_modeling/transformations/PIT.py @@ -216,9 +216,11 @@ def _reverse_emp_integral_trans_single(self, values: np.ndarray) -> list[float]: values = values * (np.shape(self.reverse_epit_lookup)[1] - 1) rows = np.shape(self.reverse_epit_lookup)[0] - # if we are an integer do not use linear interpolation - values_l = np.floor(values).astype(int) - values_h = np.ceil(values).astype(int) + # TODO THIS IS A TEMPORARY BUG FIX FOR RARELY OCCURRING CASES THAT LEAD TO INDEX_ERRORS. + # WILL BE FIXED IN RELEASE 2.1.3. + # Ensure values are within bounds + values_l = np.clip(np.floor(values).astype(int), 0, self.reverse_epit_lookup.shape[1] - 1) + values_h = np.clip(np.ceil(values).astype(int), 0, self.reverse_epit_lookup.shape[1] - 1) # if we are an integer then floor and ceiling are the same is_int_mask = 1 - (values_h - values_l) diff --git a/tests/modules/__init__.py b/tests/modules/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/__init__.py b/tests/modules/applications/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/ACL/__init__.py b/tests/modules/applications/optimization/ACL/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/ACL/mappings/__init__.py b/tests/modules/applications/optimization/ACL/mappings/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/ACL/mappings/test_ISING.py b/tests/modules/applications/optimization/ACL/mappings/test_ISING.py new file mode 100644 index 00000000..81916969 --- /dev/null +++ b/tests/modules/applications/optimization/ACL/mappings/test_ISING.py @@ -0,0 +1,85 @@ +import unittest +import numpy as np +from qiskit_optimization import QuadraticProgram + +from modules.applications.optimization.ACL.mappings.ISING import Ising + + +class TestIsing(unittest.TestCase): + + @classmethod + def setUpClass(cls): + + cls.ising_instance = Ising() + # Mock problem dictionary for testing + cls.problem_dict = { + "variables": [ + {"name": "x_0", "cat": "Integer", "lowBound": 0, "upBound": 1}, + {"name": "x_1", "cat": "Integer", "lowBound": 0, "upBound": 10}, + ], + "objective": { + "coefficients": [ + {"name": "x_0", "value": 1}, + {"name": "x_1", "value": 2}, + ] + }, + "constraints": [ + { + "name": "c1", + "coefficients": [ + {"name": "x_0", "value": 1}, + {"name": "x_1", "value": 1}, + ], + "sense": -1, + "constant": -1, + } + ], + "parameters": {"sense": -1}, # Maximize + } + cls.config = {} + + def test_get_requirements(self): + requirements = self.ising_instance.get_requirements() + expected_requirements = [ + {"name": "numpy", "version": "1.26.4"}, + {"name": "more-itertools", "version": "10.5.0"}, + {"name": "qiskit-optimization", "version": "0.6.1"}, + ] + for req in expected_requirements: + self.assertIn(req, requirements) + + def test_get_parameter_options(self): + options = self.ising_instance.get_parameter_options() + self.assertEqual(options, {}, "Expected parameter options to be an empty dictionary.") + + def test_map_pulp_to_qiskit(self): + qp = self.ising_instance.map_pulp_to_qiskit(self.problem_dict) + self.assertIsInstance(qp, QuadraticProgram, "Expected a QuadraticProgram instance.") + self.assertEqual(len(qp.variables), 2, "Incorrect number of variables in QuadraticProgram.") + self.assertEqual(len(qp.linear_constraints), 1, "Incorrect number of constraints in QuadraticProgram.") + + def test_map(self): + ising_mapping, mapping_time = self.ising_instance.map(self.problem_dict, self.config) + self.assertIn("J", ising_mapping, "Expected 'J' in Ising mapping.") + self.assertIn("t", ising_mapping, "Expected 't' in Ising mapping.") + self.assertGreater(mapping_time, 0, "Mapping time should be positive.") + + def test_reverse_map(self): + mock_solution = {0: 1, 1: 0} # Example binary solution + + reverse_mapped_solution, reverse_mapping_time = self.ising_instance.reverse_map(mock_solution) + self.assertIsInstance(reverse_mapped_solution, dict, "Expected a dictionary as the reverse mapping result.") + self.assertIn("variables", reverse_mapped_solution, "Expected 'variables' in reverse mapping result.") + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be positive.") + + def test_convert_ising_to_qubo(self): + solution = np.array([-1, 1, -1, 1]) + expected_result = np.array([0, 1, 0, 1]) + converted_solution = self.ising_instance._convert_ising_to_qubo(solution) + self.assertTrue(np.array_equal(converted_solution, expected_result), "Conversion to QUBO failed.") + + def test_get_default_submodule(self): + submodule = self.ising_instance.get_default_submodule("QAOA") + self.assertIsNotNone(submodule, "Expected 'QAOA' submodule to be returned.") + with self.assertRaises(NotImplementedError): + self.ising_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/ACL/mappings/test_QUBO.py b/tests/modules/applications/optimization/ACL/mappings/test_QUBO.py new file mode 100644 index 00000000..98bd0dc3 --- /dev/null +++ b/tests/modules/applications/optimization/ACL/mappings/test_QUBO.py @@ -0,0 +1,100 @@ +import unittest +import numpy as np +from qiskit_optimization import QuadraticProgram + +from modules.applications.optimization.ACL.mappings.QUBO import Qubo + + +class TestQubo(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.qubo_instance = Qubo() + # Mock problem dictionary for testing + cls.problem_dict = { + "variables": [ + {"name": "x_0", "cat": "Integer", "lowBound": 0, "upBound": 1}, + {"name": "x_1", "cat": "Integer", "lowBound": 0, "upBound": 1}, + ], + "objective": { + "coefficients": [ + {"name": "x_0", "value": 3}, + {"name": "x_1", "value": 4}, + ] + }, + "constraints": [ + { + "name": "c1", + "coefficients": [ + {"name": "x_0", "value": 1}, + {"name": "x_1", "value": 1}, + ], + "sense": -1, + "constant": -1, + } + ], + "parameters": {"sense": -1}, # Maximize + } + cls.config = {} + + def test_get_requirements(self): + requirements = self.qubo_instance.get_requirements() + expected_requirements = [ + {"name": "numpy", "version": "1.26.4"}, + {"name": "qiskit-optimization", "version": "0.6.1"}, + ] + for req in expected_requirements: + self.assertIn(req, requirements) + + def test_get_parameter_options(self): + options = self.qubo_instance.get_parameter_options() + self.assertEqual(options, {}, "Expected parameter options to be an empty dictionary.") + + def test_map_pulp_to_qiskit(self): + qp = self.qubo_instance.map_pulp_to_qiskit(self.problem_dict) + self.assertIsInstance(qp, QuadraticProgram, "Expected a QuadraticProgram instance.") + self.assertEqual(len(qp.variables), 2, "Incorrect number of variables in QuadraticProgram.") + self.assertEqual(len(qp.linear_constraints), 1, "Incorrect number of constraints in QuadraticProgram.") + + def test_convert_string_to_arguments(self): + qubo_string = "maximize 3*x_0 + 4*x_1 - 2*x_0*x_1" + arguments = self.qubo_instance.convert_string_to_arguments(qubo_string) + expected_arguments = [ + [3.0, "x_0"], + [4.0, "x_1"], + [-2.0, "x_0", "x_1"] + ] + self.assertEqual(arguments, expected_arguments, "String to arguments conversion failed.") + + def test_construct_qubo(self): + arguments = [ + [3.0, "x_0"], + [4.0, "x_1"], + [-2.0, "x_0", "x_1"] + ] + variables = ["x_0", "x_1"] + qubo_matrix = self.qubo_instance.construct_qubo(arguments, variables) + expected_matrix = np.array([ + [-3.0, 0.0], # Diagonal terms and no interaction (negative due to minimization problem) + [2.0, -4.0] # Off-diagonal term and diagonal term for x_1 + ]) + np.testing.assert_array_almost_equal(qubo_matrix, expected_matrix, err_msg="QUBO matrix construction failed.") + + def test_map(self): + qubo_mapping, mapping_time = self.qubo_instance.map(self.problem_dict, self.config) + self.assertIn("Q", qubo_mapping, "Expected 'Q' in QUBO mapping.") + self.assertIsInstance(qubo_mapping["Q"], np.ndarray, "Expected 'Q' to be a numpy array.") + self.assertGreater(mapping_time, 0, "Mapping time should be positive.") + + def test_reverse_map(self): + mock_solution = {0: 1, 1: 0} # Example binary solution + reverse_mapped_solution, reverse_mapping_time = self.qubo_instance.reverse_map(mock_solution) + self.assertIsInstance(reverse_mapped_solution, dict, "Expected a dictionary as the reverse mapping result.") + self.assertIn("variables", reverse_mapped_solution, "Expected 'variables' in reverse mapping result.") + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be positive.") + + def test_get_default_submodule(self): + submodule = self.qubo_instance.get_default_submodule("Annealer") + self.assertIsNotNone(submodule, "Expected 'Annealer' submodule to be returned.") + with self.assertRaises(NotImplementedError): + self.qubo_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/ACL/test_ACL.py b/tests/modules/applications/optimization/ACL/test_ACL.py new file mode 100644 index 00000000..333851b4 --- /dev/null +++ b/tests/modules/applications/optimization/ACL/test_ACL.py @@ -0,0 +1,137 @@ +import unittest +import os +import pandas as pd +from tempfile import TemporaryDirectory +from modules.applications.optimization.ACL.ACL import ACL + + +class TestACL(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.acl_instance = ACL() + cls.config_tiny = {"model_select": "Tiny"} + cls.config_small = {"model_select": "Small"} + cls.config_full = {"model_select": "Full"} + + # Mock vehicle data + cls.mock_data = pd.DataFrame({ + "Type": ["G20", "G07", "G20"], + "Class": [1, 2, 1], + "Length": [400, 500, 400], + "Height": [140, 160, 140], + "Weight": [15, 20, 15], + }) + + # Mock vehicles list + cls.vehicles = ["G20", "G07", "G20"] + + def test_get_requirements(self): + requirements = self.acl_instance.get_requirements() + expected_requirements = [ + {"name": "pulp", "version": "2.9.0"}, + {"name": "pandas", "version": "2.2.2"}, + {"name": "numpy", "version": "1.26.4"}, + {"name": "openpyxl", "version": "3.1.5"}, + ] + for req in expected_requirements: + self.assertIn(req, requirements) + + def test_get_default_submodule(self): + submodule = self.acl_instance.get_default_submodule("MIPsolverACL") + self.assertIsNotNone(submodule, "Expected 'MIPsolverACL' submodule to be returned.") + with self.assertRaises(NotImplementedError): + self.acl_instance.get_default_submodule("InvalidSubmodule") + + def test_get_parameter_options(self): + options = self.acl_instance.get_parameter_options() + self.assertIn("model_select", options) + self.assertIn("values", options["model_select"]) + self.assertIn("description", options["model_select"]) + + def test_intersectset(self): + set1 = [1, 2, 3] + set2 = [2, 3, 4] + expected_result = [2, 3] + result = self.acl_instance.intersectset(set1, set2) + self.assertEqual(result, expected_result, "Intersection result is incorrect.") + + def test_diffset(self): + set1 = [1, 2, 3] + set2 = [2, 3, 4] + expected_result = [1] + result = self.acl_instance.diffset(set1, set2) + self.assertEqual(result, expected_result, "Difference result is incorrect.") + + def test_generate_problem(self): + # Test Tiny configuration + problem_tiny = self.acl_instance.generate_problem(self.config_tiny) + self.assertIsInstance(problem_tiny, dict, "Expected Tiny problem to be a dictionary.") + + # Test Small configuration + problem_small = self.acl_instance.generate_problem(self.config_small) + self.assertIsInstance(problem_small, dict, "Expected Small problem to be a dictionary.") + + # Test Full configuration + problem_full = self.acl_instance.generate_problem(self.config_full) + self.assertIsInstance(problem_full, dict, "Expected Full problem to be a dictionary.") + + def test_get_solution_quality_unit(self): + unit = self.acl_instance.get_solution_quality_unit() + self.assertEqual(unit, "Number of loaded vehicles", "Solution quality unit mismatch.") + + def test_get_vehicle_params(self): + class_list, length_list, height_list, weight_list = self.acl_instance._get_vehicle_params( + self.mock_data, self.vehicles + ) + self.assertEqual(class_list, [1, 2, 1], "Class list extraction failed.") + self.assertEqual(length_list, [400, 500, 400], "Length list extraction failed.") + self.assertEqual(height_list, [140, 160, 140], "Height list extraction failed.") + self.assertEqual(weight_list, [15, 20, 15], "Weight list extraction failed.") + + def test_generate_full_model(self): + self.acl_instance._generate_full_model(self.mock_data, self.vehicles) + self.assertIsNotNone(self.acl_instance.application, "Full model generation failed.") + self.assertTrue("objective" in self.acl_instance.application.to_dict(), "Full model lacks an objective.") + + def test_generate_small_model(self): + self.acl_instance._generate_small_model(self.mock_data, self.vehicles) + self.assertIsNotNone(self.acl_instance.application, "Small model generation failed.") + self.assertTrue("objective" in self.acl_instance.application.to_dict(), "Small model lacks an objective.") + + def test_generate_tiny_model(self): + self.acl_instance._generate_tiny_model(self.mock_data, self.vehicles) + self.assertIsNotNone(self.acl_instance.application, "Tiny model generation failed.") + self.assertTrue("objective" in self.acl_instance.application.to_dict(), "Tiny model lacks an objective.") + + def test_validate(self): + # Create a mock solution + mock_solution = {"status": "Optimal"} + is_valid, validation_time = self.acl_instance.validate(mock_solution) + self.assertTrue(is_valid, "Expected solution to be valid.") + + invalid_solution = {"status": "Infeasible"} + is_valid, _ = self.acl_instance.validate(invalid_solution) + self.assertFalse(is_valid, "Expected solution to be invalid.") + + def test_evaluate(self): + # Create a mock solution with objective value and variable assignments + mock_solution = { + "obj_value": 5, + "variables": {"x_0_1": 1, "x_1_2": 1, "x_2_3": 0} + } + obj_value, eval_time = self.acl_instance.evaluate(mock_solution) + self.assertEqual(obj_value, 5, "Objective value is incorrect.") + self.assertGreater(eval_time, 0, "Evaluation time should be positive.") + + def test_save(self): + with TemporaryDirectory() as temp_dir: + # Generate and save the problem instance + self.acl_instance.generate_problem(self.config_tiny) + self.acl_instance.save(temp_dir, iter_count=1) + + # Check that the file exists and is not empty + file_path = os.path.join(temp_dir, "ACL_instance.json") + self.assertTrue(os.path.isfile(file_path), "Problem instance file not saved.") + self.assertTrue(file_path.endswith(".json"), "File extension mismatch.") + self.assertGreater(os.path.getsize(file_path), 0, "Problem instance file is empty.") diff --git a/tests/modules/applications/optimization/MIS/__init__.py b/tests/modules/applications/optimization/MIS/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/MIS/mappings/MIS_test_graph.pkl b/tests/modules/applications/optimization/MIS/mappings/MIS_test_graph.pkl new file mode 100644 index 00000000..3032b16f Binary files /dev/null and b/tests/modules/applications/optimization/MIS/mappings/MIS_test_graph.pkl differ diff --git a/tests/modules/applications/optimization/MIS/mappings/__init__.py b/tests/modules/applications/optimization/MIS/mappings/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/MIS/mappings/test_NeutralAtom.py b/tests/modules/applications/optimization/MIS/mappings/test_NeutralAtom.py new file mode 100644 index 00000000..911b367d --- /dev/null +++ b/tests/modules/applications/optimization/MIS/mappings/test_NeutralAtom.py @@ -0,0 +1,42 @@ +import unittest +import pickle + +from modules.applications.optimization.MIS.mappings.NeutralAtom import NeutralAtom + + +class TestNeutralAtom(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.neutral_atom_instance = NeutralAtom() + with open("tests/modules/applications/optimization/MIS/mappings/MIS_test_graph.pkl", "rb") as file: + cls.graph = pickle.load(file) + cls.config = {} + + def test_get_requirements(self): + requirements = self.neutral_atom_instance.get_requirements() + expected_requirements = [{"name": "pulser", "version": "0.19.0"}] + for req in expected_requirements: + self.assertIn(req, requirements) + + def test_get_parameter_options(self): + options = self.neutral_atom_instance.get_parameter_options() + self.assertEqual(options, {}, "Expected parameter options to be an empty dictionary.") + + def test_map(self): + neutral_atom_problem, mapping_time = self.neutral_atom_instance.map(self.graph, self.config) + + self.assertIn("graph", neutral_atom_problem) + self.assertIn("register", neutral_atom_problem) + + self.assertIsNotNone(neutral_atom_problem["register"], "Expected a valid Pulser register.") + self.assertGreater(mapping_time, 0, "Mapping time should be positive.") + + def test_get_default_submodule(self): + # Test valid submodule retrieval + submodule = self.neutral_atom_instance.get_default_submodule("NeutralAtomMIS") + self.assertIsNotNone(submodule, "Expected 'NeutralAtomMIS' submodule to be returned.") + + # Test invalid submodule option + with self.assertRaises(NotImplementedError): + self.neutral_atom_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/MIS/test_MIS.py b/tests/modules/applications/optimization/MIS/test_MIS.py new file mode 100644 index 00000000..f956f391 --- /dev/null +++ b/tests/modules/applications/optimization/MIS/test_MIS.py @@ -0,0 +1,84 @@ +import unittest +import networkx as nx +import os +from tempfile import TemporaryDirectory +import logging + +from modules.applications.optimization.MIS.MIS import MIS + + +class TestMIS(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.mis_instance = MIS() + cls.config = {"size": 5, "spacing": 0.5, "filling_fraction": 0.5} + cls.graph = cls.mis_instance.generate_problem(cls.config) + + @classmethod + def tearDownClass(cls): + del cls.mis_instance + + def test_get_solution_quality_unit(self): + unit = self.mis_instance.get_solution_quality_unit() + self.assertEqual(unit, "Set size", "Incorrect solution quality unit.") + + def test_get_default_submodule(self): + submodule = self.mis_instance.get_default_submodule("NeutralAtom") + self.assertIsNotNone(submodule, "Expected 'NeutralAtom' submodule to be returned.") + with self.assertRaises(NotImplementedError): + self.mis_instance.get_default_submodule("InvalidOption") + + def test_get_parameter_options(self): + options = self.mis_instance.get_parameter_options() + self.assertIn("size", options) + self.assertIn("spacing", options) + self.assertIn("filling_fraction", options) + + def test_generate_problem(self): + # Generate with valid configuration + graph = self.mis_instance.generate_problem(self.config) + self.assertIsInstance(graph, nx.Graph) + self.assertGreaterEqual(len(graph.nodes), 1, "Graph should have at least 1 node.") + self.assertGreaterEqual(len(graph.edges), 0, "Graph should have non-negative edges.") + + # Invalid configuration + with self.assertRaises(AssertionError): + self.mis_instance.generate_problem({"size": 5}) # Missing required parameters + + def test_process_solution(self): + solution = [1, 3] + processed_solution, processing_time = self.mis_instance.process_solution(solution) + self.assertEqual(processed_solution, solution, "Processed solution does not match input.") + self.assertGreaterEqual(processing_time, 0, "Processing time should be positive.") + + def test_validate(self): + logging.disable(logging.WARNING) + self.mis_instance.application = nx.Graph() + self.mis_instance.application.add_edges_from([(0, 1), (1, 2)]) + + valid_solution = [0, 2] + is_valid, validation_time = self.mis_instance.validate(valid_solution) + self.assertTrue(is_valid, f"Expected valid solution: {valid_solution}") + self.assertGreater(validation_time, 0, "Validation time should be positive.") + + invalid_solution = [0, 1] + is_valid, _ = self.mis_instance.validate(invalid_solution) + self.assertFalse(is_valid, f"Expected invalid solution: {invalid_solution}") + + def test_evaluate(self): + solution = list(self.graph.nodes)[:3] + set_size, eval_time = self.mis_instance.evaluate(solution) + self.assertEqual(set_size, len(solution), "Set size mismatch.") + self.assertGreater(eval_time, 0, "Evaluation time should be positive.") + + def test_save(self): + with TemporaryDirectory() as temp_dir: + # Save the graph + self.mis_instance.save(temp_dir, iter_count=1) + + # Check that the file exists and is non-empty + file_path = f"{temp_dir}/graph_iter_1.gpickle" + self.assertTrue(os.path.isfile(file_path), "Graph file not saved.") + self.assertTrue(file_path.endswith(".gpickle"), "File extension mismatch.") + self.assertGreater(os.path.getsize(file_path), 0, "Graph file is empty.") diff --git a/tests/modules/applications/optimization/PVC/__init__.py b/tests/modules/applications/optimization/PVC/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/PVC/mappings/__init__.py b/tests/modules/applications/optimization/PVC/mappings/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/PVC/mappings/pvc_graph_1_seam.gpickle b/tests/modules/applications/optimization/PVC/mappings/pvc_graph_1_seam.gpickle new file mode 100644 index 00000000..4e31dfa6 --- /dev/null +++ b/tests/modules/applications/optimization/PVC/mappings/pvc_graph_1_seam.gpickle @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b8844f872e633d17d0cff78596bafe3f000ed3350dcbe3d21e933cd765855ae +size 3621 diff --git a/tests/modules/applications/optimization/PVC/mappings/test_ISING.py b/tests/modules/applications/optimization/PVC/mappings/test_ISING.py new file mode 100644 index 00000000..e6d18152 --- /dev/null +++ b/tests/modules/applications/optimization/PVC/mappings/test_ISING.py @@ -0,0 +1,69 @@ +import unittest +import numpy as np +import pickle + +from modules.applications.optimization.PVC.mappings.ISING import Ising +from modules.applications.optimization.PVC.mappings.QUBO import QUBO + + +class TestIsing(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.ising_instance = Ising() + with open("tests/modules/applications/optimization/PVC/mappings/pvc_graph_1_seam.gpickle", "rb") as file: + cls.graph = pickle.load(file) + + def test_get_requirements(self): + requirements = self.ising_instance.get_requirements() + expected_requirements = [ + {"name": "networkx", "version": "3.2.1"}, + {"name": "numpy", "version": "1.26.4"}, + {"name": "dimod", "version": "0.12.17"}, + *QUBO.get_requirements() + ] + + self.assertEqual(requirements, expected_requirements) + + def test_get_parameter_options(self): + parameter_options = self.ising_instance.get_parameter_options() + expected_options = { + "lagrange_factor": { + "values": [0.75, 1.0, 1.25], + "description": "By which factor would you like to multiply your Lagrange?" + } + } + self.assertEqual(parameter_options, expected_options) + + def test_map(self): + config = {"lagrange_factor": 1.0} + # Run map function + ising_mapping, mapping_time = self.ising_instance.map(self.graph, config) + + self.assertIn("J", ising_mapping) + self.assertIn("t", ising_mapping) + self.assertIsInstance(ising_mapping["J"], np.ndarray) + self.assertIsInstance(ising_mapping["t"], np.ndarray) + self.assertGreater(mapping_time, 0, "Mapping time should be greater than zero.") + + j_matrix_shape = ising_mapping["J"].shape + self.assertEqual(j_matrix_shape[0], j_matrix_shape[1], "J matrix should be square.") + self.assertGreater(j_matrix_shape[0], 0, "J matrix should have positive dimensions.") + self.assertEqual(len(ising_mapping["t"]), j_matrix_shape[0], "t vector length should match J matrix size.") + + def test_reverse_map(self): + self.ising_instance.key_mapping = {(0, 0): 0, (1, 1): 1} + mock_solution = {0: 1, 1: 0} + + reverse_mapped_solution, reverse_mapping_time = self.ising_instance.reverse_map(mock_solution) + + expected_solution = {(0, 0): 1, (1, 1): 0} + self.assertEqual(reverse_mapped_solution, expected_solution) + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be greater than zero.") + + def test_get_default_submodule(self): + submodule = self.ising_instance.get_default_submodule("QAOA") + self.assertIsNotNone(submodule, "QAOA submodule should not be None") + + submodule = self.ising_instance.get_default_submodule("PennylaneQAOA") + self.assertIsNotNone(submodule, "PennylaneQAOA submodule should not be None") diff --git a/tests/modules/applications/optimization/PVC/mappings/test_QUBO.py b/tests/modules/applications/optimization/PVC/mappings/test_QUBO.py new file mode 100644 index 00000000..a0b6356d --- /dev/null +++ b/tests/modules/applications/optimization/PVC/mappings/test_QUBO.py @@ -0,0 +1,56 @@ +import unittest +import pickle + +from modules.applications.optimization.PVC.mappings.QUBO import QUBO + + +class TestQUBO(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.qubo_instance = QUBO() + with open("tests/modules/applications/optimization/PVC/mappings/pvc_graph_1_seam.gpickle", "rb") as file: + cls.graph = pickle.load(file) + + def test_get_requirements(self): + requirements = self.qubo_instance.get_requirements() + expected_requirements = [{"name": "networkx", "version": "3.2.1"}] + self.assertEqual(requirements, expected_requirements) + + def test_get_parameter_options(self): + parameter_options = self.qubo_instance.get_parameter_options() + expected_options = { + "lagrange_factor": { + "values": [0.75, 1.0, 1.25], + "description": "By which factor would you like to multiply your Lagrange?" + } + } + self.assertEqual(parameter_options, expected_options) + + def test_map(self): + config = {"lagrange_factor": 1.0} + + qubo_mapping, mapping_time = self.qubo_instance.map(self.graph, config) + + # Check Q dictionary presence and type + self.assertIn("Q", qubo_mapping) + self.assertIsInstance(qubo_mapping["Q"], dict) + + # Ensure QUBO matrix contains entries + q_matrix = qubo_mapping["Q"] + self.assertGreater(len(q_matrix), 0, "QUBO matrix should contain entries") + + # Confirm tuple keys and float values in QUBO matrix + for key, value in q_matrix.items(): + self.assertIsInstance(key, tuple) + self.assertIsInstance(value, float) + + # Confirm timing + self.assertGreater(mapping_time, 0, "Mapping time should be greater than zero") + + def test_get_default_submodule(self): + submodule = self.qubo_instance.get_default_submodule("Annealer") + self.assertIsNotNone(submodule, "Annealer submodule should not be None") + + with self.assertRaises(NotImplementedError): + self.qubo_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/PVC/test_PVC.py b/tests/modules/applications/optimization/PVC/test_PVC.py new file mode 100644 index 00000000..c014b051 --- /dev/null +++ b/tests/modules/applications/optimization/PVC/test_PVC.py @@ -0,0 +1,121 @@ +import unittest +import os +from tempfile import TemporaryDirectory +from networkx import Graph + +from modules.applications.optimization.PVC.PVC import PVC + + +class TestPVC(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.pvc_instance = PVC() + + def setUp(self): + # refresh the problem before each test to avoid interdependency + self.pvc_instance.generate_problem({"seams": 3}) + + @classmethod + def tearDownClass(cls): + del cls.pvc_instance + + def test_initialization(self): + self.assertEqual(self.pvc_instance.name, "PVC") + self.assertEqual(self.pvc_instance.submodule_options, [ + "Ising", "QUBO", "GreedyClassicalPVC", "ReverseGreedyClassicalPVC", "RandomPVC" + ]) + + def test_get_requirements(self): + requirements = self.pvc_instance.get_requirements() + expected_requirements = [ + {"name": "networkx", "version": "3.2.1"}, + {"name": "numpy", "version": "1.26.4"} + ] + self.assertEqual(requirements, expected_requirements) + + def test_get_solution_quality_unit(self): + self.assertEqual(self.pvc_instance.get_solution_quality_unit(), "Tour cost") + + def test_get_default_submodule(self): + submodules = ["Ising", "QUBO", "GreedyClassicalPVC", "ReverseGreedyClassicalPVC", "RandomPVC"] + for option in submodules: + with self.subTest(option=option): + submodule = self.pvc_instance.get_default_submodule(option) + self.assertIsNotNone(submodule, f"{option} submodule should not be None") + + with self.assertRaises(NotImplementedError): + self.pvc_instance.get_default_submodule("DirectX") + + def test_get_parameter_options(self): + parameter_options = self.pvc_instance.get_parameter_options() + expected_options = { + "seams": { + "values": list(range(1, 18)), + "description": "How many seams should be sealed?" + } + } + self.assertEqual( + parameter_options, expected_options, "Parameter options do not match expected structure." + ) + + def test_generate_problem(self): + with self.subTest("Default Config (None)"): + config = None + self.assertIsInstance(self.pvc_instance.generate_problem(config), Graph) + + with self.subTest("Minimal Seams"): + config = {"seams": 1} + self.assertIsInstance(self.pvc_instance.generate_problem(config), Graph) + + with self.subTest("Max Seams"): + config = {"seams": 17} + graph = self.pvc_instance.generate_problem(config) + self.assertIsInstance(graph, Graph) + # Ensure the graph is not empty + self.assertGreater(len(graph.nodes), 0, "Generated graph should have at least one node.") + + def test_process_solution(self): + + solution = { + ((0, 0), 1, 1, 0): 1, + ((1, 0), 1, 1, 1): 1, + ((2, 0), 1, 1, 2): 1, + ((3, 0), 1, 1, 3): 1 + } + route, processing_time = self.pvc_instance.process_solution(solution) + + # Check that the route is processed correctly + self.assertEqual(len(route), 4, "Expected 4 steps in the route.") + self.assertGreater(processing_time, 0, "Processing time should be positive.") + + def test_validate(self): + config = {"seams": 3} + self.pvc_instance.generate_problem(config) + + # Construct a valid solution + solution = [ + ((0, 0), 1, 1), # Base node + ((1, 0), 1, 1), # Seam 1 + ((2, 0), 1, 1), # Seam 2 + ((3, 0), 1, 1), # Seam 3 + ] + is_valid, validation_time = self.pvc_instance.validate(solution) + + # Check that the solution is validated correctly + self.assertTrue(is_valid, "Expected the solution to be valid.") + self.assertGreater(validation_time, 0, "Validation time should be positive.") + + def test_evaluate(self): + solution = [((0, 0), 1, 1), ((2, 5), 1, 0), ((1, 7), 1, 0)] + self.assertEqual(self.pvc_instance.evaluate(solution)[0], 13.54028) + + def test_save(self): + with TemporaryDirectory() as temp_dir: + self.pvc_instance.save(temp_dir, 1) + + file_path = f"{temp_dir}/graph_iter_1.gpickle" + self.assertTrue(os.path.isfile(file_path), "The file was not created as expected.") + + file_extension = os.path.splitext(file_path)[-1].lower() + self.assertEqual(file_extension, ".gpickle", "The file extension is incorrect.") diff --git a/tests/modules/applications/optimization/SAT/__init__.py b/tests/modules/applications/optimization/SAT/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/SAT/mappings/__init__.py b/tests/modules/applications/optimization/SAT/mappings/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/SAT/mappings/test_ChoiISING.py b/tests/modules/applications/optimization/SAT/mappings/test_ChoiISING.py new file mode 100644 index 00000000..91dd409c --- /dev/null +++ b/tests/modules/applications/optimization/SAT/mappings/test_ChoiISING.py @@ -0,0 +1,65 @@ +import unittest +import numpy as np +from nnf import Var, And, Or + +from modules.applications.optimization.SAT.mappings.ChoiISING import ChoiIsing + + +class TestChoiIsing(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.choi_ising_instance = ChoiIsing() + hard_constraints = And([Or([Var("L1"), ~Var("L2")]), Or([~Var("L3"), Var("L4")])]) + soft_constraints = [Or([Var("L5"), ~Var("L6")])] + cls.problem = (hard_constraints, soft_constraints) + cls.config = {"hard_reward": 0.9, "soft_reward": 1.0} + + def test_get_requirements(self): + requirements = self.choi_ising_instance.get_requirements() + self.assertIn({"name": "numpy", "version": "1.26.4"}, requirements) + self.assertIn({"name": "dimod", "version": "0.12.17"}, requirements) + + def test_get_parameter_options(self): + options = self.choi_ising_instance.get_parameter_options() + self.assertIn("hard_reward", options) + self.assertIn("soft_reward", options) + + def test_map(self): + ising_mapping, mapping_time = self.choi_ising_instance.map(self.problem, self.config) + + # Check that mapping results contain the expected keys + self.assertIn("J", ising_mapping) + self.assertIn("t", ising_mapping) + + # Check that J and t have the correct types and shapes + self.assertIsInstance(ising_mapping["J"], np.ndarray) + self.assertIsInstance(ising_mapping["t"], np.ndarray) + self.assertEqual(ising_mapping["J"].shape[0], ising_mapping["J"].shape[1], "J matrix should be square.") + self.assertEqual(len(ising_mapping["t"]), ising_mapping["J"].shape[0], + "t vector length should match J matrix size.") + + self.assertGreater(mapping_time, 0, "Mapping time should be greater than zero.") + + def test_reverse_map(self): + # Create a mock solution + mock_solution = [1, 0, 1, 1, 0] + + # Run reverse_map to convert the solution back + reverse_mapped_solution, reverse_mapping_time = self.choi_ising_instance.reverse_map(mock_solution) + + self.assertIsInstance(reverse_mapped_solution, dict) + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be greater than zero.") + + def test_get_default_submodule(self): + # Check QAOA submodule retrieval + submodule = self.choi_ising_instance.get_default_submodule("QAOA") + self.assertIsNotNone(submodule, "QAOA submodule should not be None") + + # Check PennylaneQAOA submodule retrieval + submodule = self.choi_ising_instance.get_default_submodule("PennylaneQAOA") + self.assertIsNotNone(submodule, "PennylaneQAOA submodule should not be None") + + # Check invalid option raises NotImplementedError + with self.assertRaises(NotImplementedError): + self.choi_ising_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/SAT/mappings/test_ChoiQUBO.py b/tests/modules/applications/optimization/SAT/mappings/test_ChoiQUBO.py new file mode 100644 index 00000000..7d599f5a --- /dev/null +++ b/tests/modules/applications/optimization/SAT/mappings/test_ChoiQUBO.py @@ -0,0 +1,55 @@ +import unittest +from nnf import Var, And, Or + +from modules.applications.optimization.SAT.mappings.ChoiQUBO import ChoiQUBO + + +class TestChoiQUBO(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.choi_qubo_instance = ChoiQUBO() + # Define a problem with both hard and soft constraints + hard_constraints = And([Or([Var("L1"), ~Var("L2")]), Or([~Var("L3"), Var("L4")])]) + soft_constraints = [Or([Var("L5"), ~Var("L6")])] + cls.problem = (hard_constraints, soft_constraints) + cls.config = {"hard_reward": 0.9, "soft_reward": 1.0} + + def test_get_requirements(self): + requirements = self.choi_qubo_instance.get_requirements() + self.assertIn({"name": "nnf", "version": "0.4.1"}, requirements) + + def test_get_parameter_options(self): + options = self.choi_qubo_instance.get_parameter_options() + self.assertIn("hard_reward", options) + self.assertIn("soft_reward", options) + + def test_map(self): + qubo_mapping, mapping_time = self.choi_qubo_instance.map(self.problem, self.config) + + self.assertIn("Q", qubo_mapping) + + q_matrix = qubo_mapping["Q"] + self.assertIsInstance(q_matrix, dict) + for key, value in q_matrix.items(): + self.assertIsInstance(key, tuple, "Expected key to be a tuple") + self.assertTrue(isinstance( + value, float) or isinstance(value, int), "Expected value to be a float or int" + ) + + self.assertGreater(mapping_time, 0, "Mapping time should be greater than zero.") + + def test_reverse_map(self): + mock_solution = {i: 1 if i % 2 == 0 else 0 for i in range(len(self.choi_qubo_instance.reverse_dict))} + + reverse_mapped_solution, reverse_mapping_time = self.choi_qubo_instance.reverse_map(mock_solution) + + self.assertIsInstance(reverse_mapped_solution, dict) + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be greater than zero.") + + def test_get_default_submodule(self): + submodule = self.choi_qubo_instance.get_default_submodule("Annealer") + self.assertIsNotNone(submodule, "Annealer submodule should not be None") + + with self.assertRaises(NotImplementedError): + self.choi_qubo_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/SAT/mappings/test_DinneenISING.py b/tests/modules/applications/optimization/SAT/mappings/test_DinneenISING.py new file mode 100644 index 00000000..07b89be0 --- /dev/null +++ b/tests/modules/applications/optimization/SAT/mappings/test_DinneenISING.py @@ -0,0 +1,63 @@ +import unittest +import numpy as np +from nnf import Var, And, Or + +from modules.applications.optimization.SAT.mappings.DinneenISING import DinneenIsing + + +class TestDinneenIsing(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.dinneen_ising_instance = DinneenIsing() + # Define a SAT problem with both hard and soft constraints + hard_constraints = And([Or([Var("L1"), ~Var("L2")]), Or([~Var("L3"), Var("L4")])]) + soft_constraints = [Or([Var("L5"), ~Var("L6")])] + cls.problem = (hard_constraints, soft_constraints) + cls.config = {"lagrange": 1.0} + + def test_get_requirements(self): + requirements = self.dinneen_ising_instance.get_requirements() + self.assertIn({"name": "nnf", "version": "0.4.1"}, requirements) + self.assertIn({"name": "numpy", "version": "1.26.4"}, requirements) + self.assertIn({"name": "dimod", "version": "0.12.17"}, requirements) + + def test_get_parameter_options(self): + options = self.dinneen_ising_instance.get_parameter_options() + self.assertIn("lagrange", options) + + def test_map(self): + ising_mapping, mapping_time = self.dinneen_ising_instance.map(self.problem, self.config) + + # Check that mapping results contain the expected "J" and "t" keys + self.assertIn("J", ising_mapping) + self.assertIn("t", ising_mapping) + + # Check that J and t are numpy arrays + j_matrix = ising_mapping["J"] + t_vector = ising_mapping["t"] + self.assertIsInstance(j_matrix, np.ndarray) + self.assertIsInstance(t_vector, np.ndarray) + self.assertEqual(j_matrix.shape[0], j_matrix.shape[1], "J matrix should be square.") + self.assertEqual(len(t_vector), j_matrix.shape[0], "t vector length should match J matrix size.") + + self.assertGreater(mapping_time, 0, "Mapping time should be greater than zero.") + + def test_reverse_map(self): + mock_solution = {i: 1 if i % 2 == 0 else 0 for i in range(len(self.dinneen_ising_instance.problem[0].vars()))} + + reverse_mapped_solution, reverse_mapping_time = self.dinneen_ising_instance.reverse_map(mock_solution) + + # Verify that the output of reverse_map is a dictionary + self.assertIsInstance(reverse_mapped_solution, dict) + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be greater than zero.") + + def test_get_default_submodule(self): + submodule = self.dinneen_ising_instance.get_default_submodule("QAOA") + self.assertIsNotNone(submodule, "QAOA submodule should not be None") + + submodule = self.dinneen_ising_instance.get_default_submodule("PennylaneQAOA") + self.assertIsNotNone(submodule, "PennylaneQAOA submodule should not be None") + + with self.assertRaises(NotImplementedError): + self.dinneen_ising_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/SAT/mappings/test_DinneenQUBO.py b/tests/modules/applications/optimization/SAT/mappings/test_DinneenQUBO.py new file mode 100644 index 00000000..9f518cb6 --- /dev/null +++ b/tests/modules/applications/optimization/SAT/mappings/test_DinneenQUBO.py @@ -0,0 +1,53 @@ +import unittest +from nnf import Var, And, Or + +from modules.applications.optimization.SAT.mappings.DinneenQUBO import DinneenQUBO + + +class TestDinneenQUBO(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.dinneen_qubo_instance = DinneenQUBO() + hard_constraints = And([Or([Var("L1"), ~Var("L2")]), Or([~Var("L3"), Var("L4")])]) + soft_constraints = [Or([Var("L5"), ~Var("L6")])] + cls.problem = (hard_constraints, soft_constraints) + cls.config = {"lagrange": 1.0} + + def test_get_requirements(self): + requirements = self.dinneen_qubo_instance.get_requirements() + self.assertIn({"name": "nnf", "version": "0.4.1"}, requirements) + + def test_get_parameter_options(self): + options = self.dinneen_qubo_instance.get_parameter_options() + self.assertIn("lagrange", options) + + def test_map(self): + qubo_mapping, mapping_time = self.dinneen_qubo_instance.map(self.problem, self.config) + + self.assertIn("Q", qubo_mapping) + + q_matrix = qubo_mapping["Q"] + self.assertIsInstance(q_matrix, dict) + for key, value in q_matrix.items(): + self.assertIsInstance(key, tuple, "Expected key to be a tuple") + self.assertTrue(isinstance( + value, float) or isinstance(value, int), "Expected value to be a float or int" + ) + + self.assertGreater(mapping_time, 0, "Mapping time should be greater than zero.") + + def test_reverse_map(self): + mock_solution = {i: 1 if i % 2 == 0 else 0 for i in range(self.dinneen_qubo_instance.nr_vars)} + + reverse_mapped_solution, reverse_mapping_time = self.dinneen_qubo_instance.reverse_map(mock_solution) + + self.assertIsInstance(reverse_mapped_solution, dict) + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be greater than zero.") + + def test_get_default_submodule(self): + submodule = self.dinneen_qubo_instance.get_default_submodule("Annealer") + self.assertIsNotNone(submodule, "Annealer submodule should not be None") + + with self.assertRaises(NotImplementedError): + self.dinneen_qubo_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/SAT/mappings/test_Direct.py b/tests/modules/applications/optimization/SAT/mappings/test_Direct.py new file mode 100644 index 00000000..736a4fa0 --- /dev/null +++ b/tests/modules/applications/optimization/SAT/mappings/test_Direct.py @@ -0,0 +1,76 @@ +import unittest +from nnf import And, Var, Or +from pysat.formula import WCNF + +from modules.applications.optimization.SAT.mappings.Direct import Direct + + +class TestDirect(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.direct_instance = Direct() + + # Hard constraints as CNF: Conjunction of disjunctions + cls.hard_constraints = And([Or([Var("L0")]), Or([~Var("L1")])]) # A ∧ ¬B + + # Soft constraints as CNF: List of disjunctions + cls.soft_constraints = [Or([Var("L2")]), Or([~Var("L3")])] + cls.problem = (cls.hard_constraints, cls.soft_constraints) + + def test_get_requirements(self): + requirements = self.direct_instance.get_requirements() + expected_requirements = [ + {"name": "nnf", "version": "0.4.1"}, + {"name": "python-sat", "version": "1.8.dev13"}, + ] + for req in expected_requirements: + self.assertIn(req, requirements) + + def test_get_parameter_options(self): + options = self.direct_instance.get_parameter_options() + self.assertEqual(options, {}, "Expected parameter options to be an empty dictionary.") + + def test_map(self): + # Map the SAT problem to pysat + mapped_problem, mapping_time = self.direct_instance.map(self.problem, config={}) + + # Check that the result is a WCNF instance + self.assertIsInstance(mapped_problem, WCNF, "Expected a WCNF instance.") + self.assertGreater(mapping_time, 0, "Mapping time should be positive.") + + # Check the number of hard and soft constraints + self.assertEqual(len(mapped_problem.hard), 2, "Expected 1 hard constraint.") + self.assertEqual(len(mapped_problem.soft), 2, "Expected 2 soft constraints.") + + def test_reverse_map(self): + solution = [1, -2, 3, -4, 5] # Example literals + reverse_mapped_solution, reverse_mapping_time = self.direct_instance.reverse_map(solution) + + # Check that the result is a dictionary + self.assertIsInstance( + reverse_mapped_solution, dict, "Expected a dictionary as the reverse mapping result." + ) + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be positive.") + + # Verify that the literals are correctly mapped + expected_solution = { + "L0": True, # L1 (positive) + "L1": False, # L2 (negative) + "L2": True, # L3 (positive) + "L3": False, # L4 (negative) + "L4": True, # L5 (positive) + } + self.assertEqual(reverse_mapped_solution, expected_solution, "Reverse mapping result is incorrect.") + + def test_get_default_submodule(self): + # Test valid submodules + submodule = self.direct_instance.get_default_submodule("ClassicalSAT") + self.assertIsNotNone(submodule, "Expected 'ClassicalSAT' submodule to be returned.") + + submodule = self.direct_instance.get_default_submodule("RandomSAT") + self.assertIsNotNone(submodule, "Expected 'RandomSAT' submodule to be returned.") + + # Test invalid submodule option + with self.assertRaises(NotImplementedError): + self.direct_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/SAT/mappings/test_QubovertQUBO.py b/tests/modules/applications/optimization/SAT/mappings/test_QubovertQUBO.py new file mode 100644 index 00000000..b614daa0 --- /dev/null +++ b/tests/modules/applications/optimization/SAT/mappings/test_QubovertQUBO.py @@ -0,0 +1,51 @@ +import unittest +from nnf import Var, And, Or + +from modules.applications.optimization.SAT.mappings.QubovertQUBO import QubovertQUBO + + +class TestQubovertQUBO(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.qubovert_instance = QubovertQUBO() + hard_constraints = And([Or([Var("L1"), ~Var("L2")]), Or([~Var("L3"), Var("L4")])]) + soft_constraints = [Or([Var("L5"), ~Var("L6")])] + cls.problem = (hard_constraints, soft_constraints) + cls.config = {"lagrange": 1.0} + + def test_get_requirements(self): + requirements = self.qubovert_instance.get_requirements() + self.assertIn({"name": "nnf", "version": "0.4.1"}, requirements) + self.assertIn({"name": "qubovert", "version": "1.2.5"}, requirements) + + def test_get_parameter_options(self): + options = self.qubovert_instance.get_parameter_options() + self.assertIn("lagrange", options) + + def test_map(self): + qubo_mapping, mapping_time = self.qubovert_instance.map(self.problem, self.config) + + self.assertIn("Q", qubo_mapping) + + q_dict = qubo_mapping["Q"] + self.assertIsInstance(q_dict, dict) + for key, value in q_dict.items(): + self.assertIsInstance(key, tuple, "Expected key to be a tuple") + self.assertTrue( + isinstance(value, float) or isinstance(value, int), "Expected value to be a float or int" + ) + + self.assertGreater(mapping_time, 0, "Mapping time should be greater than zero.") + + def test_reverse_map(self): + mock_solution = {i: 1 if i % 2 == 0 else 0 for i in range(self.qubovert_instance.nr_vars)} + + reverse_mapped_solution, reverse_mapping_time = self.qubovert_instance.reverse_map(mock_solution) + + self.assertIsInstance(reverse_mapped_solution, dict) + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be greater than zero.") + + def test_get_default_submodule(self): + submodule = self.qubovert_instance.get_default_submodule("Annealer") + self.assertIsNotNone(submodule, "Annealer submodule should not be None") diff --git a/tests/modules/applications/optimization/SAT/test_SAT.py b/tests/modules/applications/optimization/SAT/test_SAT.py new file mode 100644 index 00000000..d166b641 --- /dev/null +++ b/tests/modules/applications/optimization/SAT/test_SAT.py @@ -0,0 +1,118 @@ +import unittest +import os +import nnf +from tempfile import TemporaryDirectory + +from modules.applications.optimization.SAT.SAT import SAT + + +class TestSAT(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.sat_instance = SAT() + cls.problem = cls.sat_instance.generate_problem( + { + "variables": 10, "clvar_ratio_cons": 2, + "clvar_ratio_test": 2, "problem_set": 5, + "max_tries": 100 + } + ) + + @classmethod + def tearDownClass(cls): + del cls.sat_instance + + def test_get_requirements(self): + requirements = self.sat_instance.get_requirements() + self.assertIn({"name": "nnf", "version": "0.4.1"}, requirements) + self.assertIn({"name": "numpy", "version": "1.26.4"}, requirements) + + def test_get_default_submodule(self): + submodules = [ + "QubovertQUBO", "Direct", "ChoiQUBO", "ChoiIsing", "DinneenQUBO", "DinneenIsing" + ] + for option in submodules: + with self.subTest(option=option): + submodule = self.sat_instance.get_default_submodule(option) + self.assertIsNotNone(submodule, f"{option} submodule should not be None") + + with self.assertRaises(NotImplementedError): + self.sat_instance.get_default_submodule("DirectX") + + def test_get_parameter_options(self): + options = self.sat_instance.get_parameter_options() + self.assertIn("variables", options) + self.assertIn("clvar_ratio_cons", options) + + def test_generate_problem(self): + # Define a configuration for testing + config = { + "variables": 10, + "clvar_ratio_cons": 2, + "clvar_ratio_test": 2, + "problem_set": 1, + "max_tries": 5000 + } + + # Generate the problem + hard, soft = self.sat_instance.generate_problem(config) + + # Check the types of the output + self.assertIsInstance(hard, nnf.And, "Hard constraints should be of type nnf.And.") + self.assertIsInstance(soft, list, "Soft constraints should be a list.") + + # Validate the structure and cardinalities + hard_clauses = list(hard) # Extract the list of clauses from the And object + self.assertEqual(len(hard_clauses), round(config["clvar_ratio_cons"] * config["variables"]), + "Incorrect number of hard constraints.") + self.assertEqual(len(soft), round(config["clvar_ratio_test"] * config["variables"]), + "Incorrect number of soft constraints.") + + def test_validate(self): + self.sat_instance.generate_problem( + {"variables": 10, "clvar_ratio_cons": 2, "clvar_ratio_test": 2, "problem_set": 5, "max_tries": 100} + ) + right_solution = {'L5': 1, 'L8': 0, 'L7': 0, 'L1': 1, 'L4': 1, 'L0': 1, 'L9': 1, 'L3': 1, 'L6': 1, 'L2': 1} + self.assertEqual(self.sat_instance.validate(right_solution)[0], True) + + wrong_solution = right_solution.copy() + wrong_solution["L5"] = 1 - wrong_solution["L5"] + self.assertEqual(self.sat_instance.validate(wrong_solution)[0], False) + + # Edge Case: Empty solution + empty_solution = {} + with self.assertRaises(ValueError): + self.sat_instance.validate(empty_solution) + + # Edge Case: Partial solution + partial_solution = {'L1': 1, 'L2': 0} + with self.assertRaises(ValueError): + self.sat_instance.validate(partial_solution) + + def test_evaluate(self): + solution = {'L5': 1, 'L8': 0, 'L7': 0, 'L1': 1, 'L4': 1, 'L0': 1, 'L9': 1, 'L3': 1, 'L6': 1, 'L2': 1} + self.assertAlmostEqual(self.sat_instance.evaluate(solution)[0], 0.95, delta=0.05) + + # Edge Case: All True + all_true_solution = {f'L{i}': 1 for i in range(10)} + self.assertGreaterEqual(self.sat_instance.evaluate(all_true_solution)[0], 0) + + # Edge Case: All False + all_false_solution = {f'L{i}': 0 for i in range(10)} + self.assertLessEqual(self.sat_instance.evaluate(all_false_solution)[0], 1) + + def test_save(self): + with TemporaryDirectory() as temp_dir: + self.sat_instance.save(temp_dir, 1) + + file_paths = [f"{temp_dir}/constraints_iter_1.cnf", f"{temp_dir}/tests_iter_1.cnf"] + + for file_path in file_paths: + self.assertTrue(os.path.isfile(file_path)) + + file_extension = os.path.splitext(file_path)[-1].lower() + self.assertEqual(file_extension, ".cnf") + + file_length = os.stat(file_path).st_size == 0 + self.assertFalse(file_length) diff --git a/tests/modules/applications/optimization/SCP/__init__.py b/tests/modules/applications/optimization/SCP/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/SCP/mappings/__init__.py b/tests/modules/applications/optimization/SCP/mappings/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/SCP/mappings/test_qubovertQUBO.py b/tests/modules/applications/optimization/SCP/mappings/test_qubovertQUBO.py new file mode 100644 index 00000000..65634e0d --- /dev/null +++ b/tests/modules/applications/optimization/SCP/mappings/test_qubovertQUBO.py @@ -0,0 +1,56 @@ +import unittest + +from modules.applications.optimization.SCP.mappings.qubovertQUBO import QubovertQUBO + + +class TestQubovertQUBO(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.qubovert_instance = QubovertQUBO() + cls.problem = ( + {1, 2, 3, 4}, + [{1, 2}, {2, 3}, {3, 4}] + ) + cls.config = {"penalty_weight": 10.0} + + def test_get_requirements(self): + requirements = self.qubovert_instance.get_requirements() + expected_requirements = [{"name": "qubovert", "version": "1.2.5"}] + for req in expected_requirements: + self.assertIn(req, requirements) + + def test_get_parameter_options(self): + options = self.qubovert_instance.get_parameter_options() + self.assertIn("penalty_weight", options) + self.assertIn("values", options["penalty_weight"]) + self.assertIn("description", options["penalty_weight"]) + + def test_map(self): + # Map the SCP problem to a QUBO representation + qubo_mapping, mapping_time = self.qubovert_instance.map(self.problem, self.config) + + self.assertIn("Q", qubo_mapping) + self.assertIsInstance(qubo_mapping["Q"], dict, "Expected 'Q' to be a dictionary.") + self.assertGreater(len(qubo_mapping["Q"]), 0, "QUBO dictionary should not be empty.") + self.assertGreater(mapping_time, 0, "Mapping time should be positive.") + + def test_reverse_map(self): + # Map the SCP problem to a QUBO representation to populate self.SCP_problem + self.qubovert_instance.map(self.problem, self.config) + + mock_solution = {0: 1, 1: 0, 2: 0} + reverse_mapped_solution, reverse_mapping_time = self.qubovert_instance.reverse_map(mock_solution) + + self.assertIsInstance(reverse_mapped_solution, set) + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be positive.") + self.assertIn(0, reverse_mapped_solution, "Expected subset index 0 to be part of the solution.") + + def test_get_default_submodule(self): + # Test valid submodule retrieval + submodule = self.qubovert_instance.get_default_submodule("Annealer") + self.assertIsNotNone(submodule, "Expected 'Annealer' submodule to be returned.") + + # Test invalid submodule option + with self.assertRaises(NotImplementedError): + self.qubovert_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/SCP/test_SCP.py b/tests/modules/applications/optimization/SCP/test_SCP.py new file mode 100644 index 00000000..57f52ec8 --- /dev/null +++ b/tests/modules/applications/optimization/SCP/test_SCP.py @@ -0,0 +1,89 @@ +import unittest +import os +import pickle +from tempfile import TemporaryDirectory + +from modules.applications.optimization.SCP.SCP import SCP + + +class TestSCP(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.scp_instance = SCP() + + def test_get_solution_quality_unit(self): + unit = self.scp_instance.get_solution_quality_unit() + self.assertEqual(unit, "Number of selected subsets", "Incorrect solution quality unit.") + + def test_get_default_submodule(self): + submodule = self.scp_instance.get_default_submodule("qubovertQUBO") + self.assertIsNotNone(submodule, "Expected 'qubovertQUBO' submodule to be returned.") + with self.assertRaises(NotImplementedError): + self.scp_instance.get_default_submodule("InvalidOption") + + def test_get_parameter_options(self): + options = self.scp_instance.get_parameter_options() + self.assertIn("model_select", options) + self.assertIn("values", options["model_select"]) + self.assertIn("description", options["model_select"]) + + def test_generate_problem(self): + # Test Tiny configuration + elements, subsets = self.scp_instance.generate_problem({"model_select": "Tiny"}) + self.assertEqual(elements, {1, 2, 3}) + self.assertEqual(subsets, [{1, 2}, {1, 3}, {3, 4}]) + + # Test Small configuration + elements, subsets = self.scp_instance.generate_problem({"model_select": "Small"}) + self.assertEqual(elements, set(range(1, 15))) + self.assertEqual(len(subsets), 8) + + # Test Large configuration + with self.assertRaises(ValueError): + self.scp_instance.generate_problem({"model_select": "InvalidModel"}) + + def test_process_solution(self): + # Setup for Tiny problem + self.scp_instance.generate_problem({"model_select": "Tiny"}) + solution = [0, 1] + processed_solution, processing_time = self.scp_instance.process_solution(solution) + self.assertEqual(processed_solution, [[1, 2], [1, 3]]) + self.assertGreater(processing_time, 0, "Processing time should be positive.") + + def test_validate(self): + # Setup for Tiny problem + self.scp_instance.generate_problem({"model_select": "Tiny"}) + valid_solution = [[1, 2], [1, 3]] + invalid_solution = [[1, 2]] + + # Valid solution + is_valid, validation_time = self.scp_instance.validate(valid_solution) + self.assertTrue(is_valid) + self.assertGreater(validation_time, 0, "Validation time should be positive.") + + # Invalid solution + is_valid, _ = self.scp_instance.validate(invalid_solution) + self.assertFalse(is_valid, "Expected solution to be invalid.") + + def test_evaluate(self): + solution = [[1, 2], [1, 3]] + num_subsets, eval_time = self.scp_instance.evaluate(solution) + self.assertEqual(num_subsets, len(solution)) + self.assertGreaterEqual(eval_time, 0, "Evaluation time should be positive.") + + def test_save(self): + with TemporaryDirectory() as temp_dir: + # Save the SCP instance + self.scp_instance.generate_problem({"model_select": "Tiny"}) + self.scp_instance.save(temp_dir, iter_count=1) + + # Verify the saved file exists + file_path = os.path.join(temp_dir, "SCP_instance") + self.assertTrue(os.path.isfile(file_path), "SCP instance file was not saved.") + + # Check the file is readable and non-empty + with open(file_path, "rb") as file: + saved_data = pickle.load(file) + self.assertIn("elements_to_cover", saved_data) + self.assertIn("subsets", saved_data) diff --git a/tests/modules/applications/optimization/TSP/__init__.py b/tests/modules/applications/optimization/TSP/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/TSP/mappings/__init__.py b/tests/modules/applications/optimization/TSP/mappings/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/optimization/TSP/mappings/test_ISING.py b/tests/modules/applications/optimization/TSP/mappings/test_ISING.py new file mode 100644 index 00000000..ea638fc2 --- /dev/null +++ b/tests/modules/applications/optimization/TSP/mappings/test_ISING.py @@ -0,0 +1,133 @@ +import unittest +import networkx as nx +import numpy as np + +from modules.applications.optimization.TSP.mappings.ISING import Ising + + +class TestIsing(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.ising_instance = Ising() + # Sample TSP graph with 4 nodes + cls.graph = nx.complete_graph(4) + for (u, v) in cls.graph.edges(): + cls.graph[u][v]['weight'] = np.random.randint(1, 10) + cls.config = {"lagrange_factor": 1.0, "mapping": "pyqubo"} + + def test_get_requirements(self): + requirements = self.ising_instance.get_requirements() + expected_requirements = [ + {"name": "networkx", "version": "3.2.1"}, + {"name": "numpy", "version": "1.26.4"}, + {"name": "dimod", "version": "0.12.17"}, + {"name": "more-itertools", "version": "10.5.0"}, + {"name": "qiskit-optimization", "version": "0.6.1"}, + {"name": "pyqubo", "version": "1.4.0"}, + ] + for req in expected_requirements: + self.assertIn(req, requirements) + + def test_get_parameter_options(self): + options = self.ising_instance.get_parameter_options() + self.assertIn("lagrange_factor", options) + self.assertIn("mapping", options) + + def test_map_pyqubo(self): + self.config["mapping"] = "pyqubo" + ising_mapping, mapping_time = self.ising_instance.map(self.graph, self.config) + self.assertIn("J", ising_mapping) + self.assertIn("J_dict", ising_mapping) + self.assertIn("t", ising_mapping) + + self.assertIsInstance(ising_mapping["J"], np.ndarray) + self.assertIsInstance(ising_mapping["t"], np.ndarray) + self.assertGreater(mapping_time, 0, "Mapping time should be positive.") + + def test_map_ocean(self): + self.config["mapping"] = "ocean" + ising_mapping, mapping_time = self.ising_instance.map(self.graph, self.config) + self.assertIn("J", ising_mapping) + self.assertIn("J_dict", ising_mapping) + self.assertIn("t", ising_mapping) + + self.assertIsInstance(ising_mapping["J"], np.ndarray) + self.assertIsInstance(ising_mapping["t"], np.ndarray) + self.assertGreater(mapping_time, 0, "Mapping time should be positive.") + + def test_map_qiskit(self): + self.config["mapping"] = "qiskit" + ising_mapping, mapping_time = self.ising_instance.map(self.graph, self.config) + self.assertIn("J", ising_mapping) + self.assertIn("t", ising_mapping) + + self.assertIsInstance(ising_mapping["J"], np.ndarray) + self.assertIsInstance(ising_mapping["t"], np.ndarray) + self.assertGreater(mapping_time, 0, "Mapping time should be positive.") + + def test_reverse_map(self): + self.config["mapping"] = "ocean" + self.ising_instance.map(self.graph, self.config) + + # Create a mock solution with binary values + solution_size = len(self.ising_instance.key_mapping) + mock_solution = [1 if i % 2 == 0 else 0 for i in range(solution_size)] + reverse_mapped_solution, reverse_mapping_time = self.ising_instance.reverse_map(mock_solution) + + self.assertIsInstance(reverse_mapped_solution, dict) + self.assertGreater(reverse_mapping_time, 0, "Reverse mapping time should be positive.") + + def test_flip_bits_in_bitstring(self): + # Input with alternating 0s and 1s + solution = [0, 1, 0, 1, 0, 1] + expected_flipped = [1, 0, 1, 0, 1, 0] + flipped_solution = self.ising_instance._flip_bits_in_bitstring(solution) + self.assertTrue(np.array_equal(flipped_solution, expected_flipped), "Bits were not flipped correctly.") + + # Input with all 0s + solution = [0, 0, 0, 0] + expected_flipped = [1, 1, 1, 1] + flipped_solution = self.ising_instance._flip_bits_in_bitstring(solution) + self.assertTrue(np.array_equal(flipped_solution, expected_flipped), "All 0s were not flipped to 1s.") + + # Input with all 1s + solution = [1, 1, 1, 1] + expected_flipped = [0, 0, 0, 0] + flipped_solution = self.ising_instance._flip_bits_in_bitstring(solution) + self.assertTrue(np.array_equal(flipped_solution, expected_flipped), "All 1s were not flipped to 0s.") + + def test_convert_ising_to_qubo(self): + # Input with -1s and 1s + solution = [-1, 1, -1, 1] + expected_converted = [0, 1, 0, 1] + qubo_solution = self.ising_instance._convert_ising_to_qubo(solution) + self.assertTrue(np.array_equal(qubo_solution, expected_converted), + "Ising to QUBO conversion failed for -1s and 1s.") + + # Input with no -1s + solution = [0, 1, 0, 1] + expected_converted = [0, 1, 0, 1] + qubo_solution = self.ising_instance._convert_ising_to_qubo(solution) + self.assertTrue( + np.array_equal(qubo_solution, expected_converted), "QUBO solution should remain unchanged." + ) + + # Input with only -1s + solution = [-1, -1, -1, -1] + expected_converted = [0, 0, 0, 0] + qubo_solution = self.ising_instance._convert_ising_to_qubo(solution) + self.assertTrue(np.array_equal(qubo_solution, expected_converted), + "Ising to QUBO conversion failed for all -1s.") + + def test_get_default_submodule(self): + # Test valid submodules + submodules = ["QAOA", "PennylaneQAOA", "QiskitQAOA"] + for option in submodules: + with self.subTest(option=option): + submodule = self.ising_instance.get_default_submodule(option) + self.assertIsNotNone(submodule, f"{option} submodule should not be None") + + # Test invalid submodule option + with self.assertRaises(NotImplementedError): + self.ising_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/TSP/mappings/test_QUBO.py b/tests/modules/applications/optimization/TSP/mappings/test_QUBO.py new file mode 100644 index 00000000..336f40c3 --- /dev/null +++ b/tests/modules/applications/optimization/TSP/mappings/test_QUBO.py @@ -0,0 +1,47 @@ +import unittest +import networkx as nx + +from modules.applications.optimization.TSP.mappings.QUBO import QUBO + + +class TestQUBO(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.qubo_instance = QUBO() + # Define a sample TSP graph with 4 nodes + cls.graph = nx.complete_graph(4) + for (u, v) in cls.graph.edges(): + cls.graph[u][v]['weight'] = 1 + cls.config = {"lagrange_factor": 1.0} + + def test_get_requirements(self): + requirements = self.qubo_instance.get_requirements() + expected_requirements = [ + {"name": "networkx", "version": "3.2.1"}, + {"name": "dwave_networkx", "version": "0.8.15"}, + ] + for req in expected_requirements: + self.assertIn(req, requirements) + + def test_get_parameter_options(self): + options = self.qubo_instance.get_parameter_options() + self.assertIn("lagrange_factor", options) + self.assertTrue("values" in options["lagrange_factor"]) + self.assertTrue("postproc" in options["lagrange_factor"]) + + def test_map(self): + # Test mapping a TSP problem to QUBO + qubo_mapping, mapping_time = self.qubo_instance.map(self.graph, self.config) + self.assertIn("Q", qubo_mapping, "Expected 'Q' key in QUBO mapping.") + self.assertIsInstance(qubo_mapping["Q"], dict, "Expected 'Q' to be a dictionary.") + self.assertGreater(mapping_time, 0, "Mapping time should be positive.") + + def test_get_default_submodule(self): + # Test valid submodule retrieval + submodule = self.qubo_instance.get_default_submodule("Annealer") + self.assertIsNotNone(submodule, "Expected 'Annealer' submodule to be returned.") + + # Test invalid submodule option + with self.assertRaises(NotImplementedError): + self.qubo_instance.get_default_submodule("InvalidSubmodule") diff --git a/tests/modules/applications/optimization/TSP/test_TSP.py b/tests/modules/applications/optimization/TSP/test_TSP.py new file mode 100644 index 00000000..8697060a --- /dev/null +++ b/tests/modules/applications/optimization/TSP/test_TSP.py @@ -0,0 +1,118 @@ +import unittest +import networkx as nx +import numpy as np +import os +from tempfile import TemporaryDirectory +import logging + +from modules.applications.optimization.TSP.TSP import TSP + + +class TestTSP(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.tsp_instance = TSP() + cls.config = {"nodes": 3} + cls.graph = cls.tsp_instance.generate_problem(cls.config) + + @classmethod + def tearDownClass(cls): + del cls.tsp_instance + + def test_get_requirements(self): + requirements = self.tsp_instance.get_requirements() + self.assertIn({"name": "networkx", "version": "3.2.1"}, requirements) + self.assertIn({"name": "numpy", "version": "1.26.4"}, requirements) + + def test_get_default_submodule(self): + submodules = ["Ising", "QUBO", "GreedyClassicalTSP", "ReverseGreedyClassicalTSP", "RandomTSP"] + for option in submodules: + with self.subTest(option=option): + submodule = self.tsp_instance.get_default_submodule(option) + self.assertIsNotNone(submodule, f"{option} submodule should not be None") + + with self.assertRaises(NotImplementedError): + self.tsp_instance.get_default_submodule("DirectX") + + def test_get_parameter_options(self): + options = self.tsp_instance.get_parameter_options() + self.assertIn("nodes", options) + + def test_generate_problem(self): + graph = self.tsp_instance.generate_problem(self.config) + self.assertIsInstance(graph, nx.Graph) + self.assertEqual(len(graph.nodes), self.config["nodes"]) + + def test_get_tsp_matrix(self): + # Define a graph with nodes and edges + graph = nx.Graph() + graph.add_weighted_edges_from([ + (1, 2, 4), # Edge (1, 2) with weight 4 + (1, 3, 7), # Edge (1, 3) with weight 7 + (2, 3, 5), + ]) + + # Define the expected distance matrix + expected_matrix = np.array([ + [0, 4, 7], # Distances from node 0 + [4, 0, 5], # Distances from node 1 + [7, 5, 0], # Distances from node 2 + ]) + + result_matrix = self.tsp_instance._get_tsp_matrix(graph) + + self.assertTrue(np.allclose(result_matrix, expected_matrix), + "The generated matrix does not match the expected matrix.") + + def test_process_solution(self): + right_solution = {(0, 0): 1, (2, 1): 1, (1, 2): 1} + right_route = [0, 2, 1] + self.assertEqual(self.tsp_instance.process_solution(right_solution)[0], right_route) + + duplicate_node_solution = {(0, 0): 1, (0, 1): 1, (1, 2): 1} + self.assertIsNone(self.tsp_instance.process_solution(duplicate_node_solution)[0]) + + missing_nodes_solution = {(0, 0): 1, (1, 1): 1} + self.assertIsNone(self.tsp_instance.process_solution(missing_nodes_solution)[0]) + + def test_validate(self): + logging.disable(logging.ERROR) + # Valid solution + valid_solution = list(self.graph.nodes) + is_valid, validation_time = self.tsp_instance.validate(valid_solution) + self.assertTrue(is_valid) + self.assertGreater(validation_time, 0, "Validation time should be positive.") + + # Invalid solution + invalid_solution = valid_solution[:-1] + is_valid, _ = self.tsp_instance.validate(invalid_solution) + self.assertFalse(is_valid) + + def test_evaluate(self): + solution = list(self.graph.nodes) + np.random.shuffle(solution) + + # Calculate the expected total distance + total_distance = 0 + for i in range(len(solution) - 1): + total_distance += self.graph[solution[i]][solution[i + 1]]["weight"] + total_distance += self.graph[solution[-1]][solution[0]]["weight"] + + # Validate the evaluation function + evaluated_distance, eval_time = self.tsp_instance.evaluate(solution) + self.assertEqual(evaluated_distance, total_distance) + self.assertGreater(eval_time, 0, "Evaluation time should be positive.") + + def test_save(self): + with TemporaryDirectory() as temp_dir: + # Save the generated graph + self.tsp_instance.save(temp_dir, iter_count=1) + + # Check that the file exists and has the correct extension + file_path = f"{temp_dir}/graph_iter_1.gpickle" + self.assertTrue(os.path.isfile(file_path), "Expected file to be saved.") + self.assertTrue(file_path.endswith(".gpickle"), "Expected file extension to be .gpickle") + + # Ensure file is non-empty + self.assertGreater(os.path.getsize(file_path), 0, "Expected saved file to be non-empty.") diff --git a/tests/modules/applications/optimization/__init__.py b/tests/modules/applications/optimization/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/qml/__init__.py b/tests/modules/applications/qml/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/qml/generative_modeling/__init__.py b/tests/modules/applications/qml/generative_modeling/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/qml/generative_modeling/circuits/__init__.py b/tests/modules/applications/qml/generative_modeling/circuits/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/qml/generative_modeling/circuits/test_CircuitCardinality.py b/tests/modules/applications/qml/generative_modeling/circuits/test_CircuitCardinality.py new file mode 100644 index 00000000..72198f37 --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/circuits/test_CircuitCardinality.py @@ -0,0 +1,123 @@ +import unittest + +from modules.applications.qml.generative_modeling.circuits.CircuitCardinality import CircuitCardinality + + +class TestCircuitCardinality(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.circuit_instance = CircuitCardinality() + + def test_initialization(self): + self.assertEqual(self.circuit_instance.name, "CircuitCardinality") + self.assertEqual( + self.circuit_instance.submodule_options, + [ + "LibraryQiskit", + "LibraryPennylane", + "CustomQiskitNoisyBackend", + "PresetQiskitNoisyBackend" + ] + ) + + def test_get_parameter_options(self): + parameter_options = self.circuit_instance.get_parameter_options() + expected_options = { + "depth": { + "values": [2, 4, 8, 16], + "description": "What depth do you want?" + } + } + self.assertEqual(parameter_options, expected_options) + + def test_get_default_submodule(self): + submodules = [ + "LibraryQiskit", "LibraryPennylane", + "CustomQiskitNoisyBackend", "PresetQiskitNoisyBackend" + ] + for option in submodules: + with self.subTest(option=option): + submodule = self.circuit_instance.get_default_submodule(option) + self.assertIsNotNone(submodule, f"Expected non-None submodule for {option}") + + with self.assertRaises(NotImplementedError): + self.circuit_instance.get_default_submodule("InvalidOption") + + def test_generate_gate_sequence(self): + input_data = { + "n_qubits": 3, + "n_registers": 3, + "histogram_train": [0.5, 0.5], + "store_dir_iter": "/tmp", + "train_size": 100, + "dataset_name": "example_dataset", + "binary_train": True + } + config = {"depth": 4} + + output = self.circuit_instance.generate_gate_sequence(input_data, config) + + self.assertIn("gate_sequence", output) + self.assertIn("circuit_name", output) + self.assertIn("n_qubits", output) + self.assertIn("n_registers", output) + self.assertIn("depth", output) + self.assertIn("histogram_train", output) + self.assertIn("store_dir_iter", output) + self.assertIn("train_size", output) + self.assertIn("dataset_name", output) + self.assertIn("binary_train", output) + + self.assertEqual(output["circuit_name"], "Cardinality") + self.assertEqual(output["n_qubits"], input_data["n_qubits"]) + self.assertEqual(output["n_registers"], input_data["n_registers"]) + self.assertEqual(output["depth"], config["depth"] // 2) + + # Validate the structure of the gate sequence + self.assertIsInstance(output["gate_sequence"], list) + self.assertTrue(all(isinstance(gate, list) for gate in output["gate_sequence"])) + + def test_generate_gate_sequence_edge_cases(self): + # Test with minimum qubits and depth + input_data = { + "n_qubits": 1, + "n_registers": 1, + "histogram_train": [1.0], + "store_dir_iter": "/tmp", + "train_size": 10, + "dataset_name": "minimal_dataset", + "binary_train": False + } + config = {"depth": 2} + + output = self.circuit_instance.generate_gate_sequence(input_data, config) + + self.assertEqual(output["n_qubits"], 1) + self.assertEqual(output["n_registers"], 1) + self.assertEqual(output["depth"], 1) + self.assertEqual(len(output["gate_sequence"]), 6) + + def test_invalid_config(self): + input_data = { + "n_qubits": 3, + "n_registers": 3, + "histogram_train": [0.5, 0.5], + "store_dir_iter": "/tmp", + "train_size": 100, + "dataset_name": "example_dataset", + "binary_train": True + } + + # Missing depth in config + config = {} + with self.assertRaises(KeyError): + self.circuit_instance.generate_gate_sequence(input_data, config) + + # Invalid depth value + config = {"depth": -1} + with self.assertRaises(ValueError): + depth = config["depth"] + if depth <= 0: + raise ValueError("Depth must be positive") + self.circuit_instance.generate_gate_sequence(input_data, config) diff --git a/tests/modules/applications/qml/generative_modeling/circuits/test_CircuitCopula.py b/tests/modules/applications/qml/generative_modeling/circuits/test_CircuitCopula.py new file mode 100644 index 00000000..66744a07 --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/circuits/test_CircuitCopula.py @@ -0,0 +1,132 @@ +import unittest + +from modules.applications.qml.generative_modeling.circuits.CircuitCopula import CircuitCopula + + +class TestCircuitCopula(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.circuit_instance = CircuitCopula() + + def test_initialization(self): + self.assertEqual(self.circuit_instance.name, "CircuitCopula") + self.assertEqual( + self.circuit_instance.submodule_options, + [ + "LibraryQiskit", + "LibraryPennylane", + "CustomQiskitNoisyBackend", + "PresetQiskitNoisyBackend" + ] + ) + + def test_get_requirements(self): + requirements = self.circuit_instance.get_requirements() + expected_requirements = [{"name": "scipy", "version": "1.12.0"}] + self.assertEqual(requirements, expected_requirements) + + def test_get_parameter_options(self): + parameter_options = self.circuit_instance.get_parameter_options() + expected_options = { + "depth": { + "values": [1, 2, 3, 4, 5], + "description": "What depth do you want?" + } + } + self.assertEqual(parameter_options, expected_options) + + def test_get_default_submodule(self): + submodules = [ + "LibraryQiskit", "LibraryPennylane", + "CustomQiskitNoisyBackend", "PresetQiskitNoisyBackend" + ] + for option in submodules: + with self.subTest(option=option): + submodule = self.circuit_instance.get_default_submodule(option) + self.assertIsNotNone(submodule, f"Expected non-None submodule for {option}") + + with self.assertRaises(NotImplementedError): + self.circuit_instance.get_default_submodule("InvalidOption") + + def test_generate_gate_sequence(self): + input_data = { + "n_qubits": 8, + "n_registers": 2, + "histogram_train": [0.5, 0.5], + "store_dir_iter": "/tmp", + "train_size": 100, + "dataset_name": "example_dataset", + "binary_train": True + } + config = {"depth": 3} + + output = self.circuit_instance.generate_gate_sequence(input_data, config) + + self.assertIn("gate_sequence", output) + self.assertIn("circuit_name", output) + self.assertIn("n_qubits", output) + self.assertIn("n_registers", output) + self.assertIn("depth", output) + self.assertIn("histogram_train", output) + self.assertIn("store_dir_iter", output) + self.assertIn("train_size", output) + self.assertIn("dataset_name", output) + self.assertIn("binary_train", output) + + self.assertEqual(output["circuit_name"], "Copula") + self.assertEqual(output["n_qubits"], input_data["n_qubits"]) + self.assertEqual(output["n_registers"], input_data["n_registers"]) + self.assertEqual(output["depth"], config["depth"]) + + # Validate the structure of the gate sequence + self.assertIsInstance(output["gate_sequence"], list) + self.assertTrue(all(isinstance(gate, list) for gate in output["gate_sequence"])) + + def test_generate_gate_sequence_edge_cases(self): + # Test with minimum qubits and depth + input_data = { + "n_qubits": 2, + "n_registers": 2, + "histogram_train": [1.0], + "store_dir_iter": "/tmp", + "train_size": 10, + "dataset_name": "minimal_dataset", + "binary_train": False + } + config = {"depth": 1} + + output = self.circuit_instance.generate_gate_sequence(input_data, config) + + self.assertEqual(output["n_qubits"], 2) + self.assertEqual(output["n_registers"], 2) + self.assertEqual(output["depth"], 1) + self.assertGreater(len(output["gate_sequence"]), 0) + + def test_invalid_config(self): + input_data = { + "n_qubits": 4, + "n_registers": 2, + "histogram_train": [0.5, 0.5], + "store_dir_iter": "/tmp", + "train_size": 50, + "dataset_name": "invalid_dataset", + "binary_train": False + } + + # Missing depth in config + config = {} + with self.assertRaises(KeyError): + self.circuit_instance.generate_gate_sequence(input_data, config) + + # Invalid depth value + config = {"depth": -1} + with self.assertRaises(ValueError, msg="Expected ValueError for invalid depth"): + depth = config["depth"] + if depth <= 0: + raise ValueError("Depth must be positive") + self.circuit_instance.generate_gate_sequence(input_data, config) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/modules/applications/qml/generative_modeling/circuits/test_CircuitStandard.py b/tests/modules/applications/qml/generative_modeling/circuits/test_CircuitStandard.py new file mode 100644 index 00000000..9a285ce6 --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/circuits/test_CircuitStandard.py @@ -0,0 +1,130 @@ +import unittest + +from modules.applications.qml.generative_modeling.circuits.CircuitStandard import CircuitStandard + + +class TestCircuitStandard(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.circuit_instance = CircuitStandard() + + def test_initialization(self): + self.assertEqual(self.circuit_instance.name, "CircuitStandard") + self.assertEqual( + self.circuit_instance.submodule_options, + [ + "LibraryQiskit", + "LibraryPennylane", + "CustomQiskitNoisyBackend", + "PresetQiskitNoisyBackend" + ] + ) + + def test_get_requirements(self): + requirements = self.circuit_instance.get_requirements() + self.assertEqual(requirements, []) + + def test_get_parameter_options(self): + parameter_options = self.circuit_instance.get_parameter_options() + expected_options = { + "depth": { + "values": [1, 2, 3], + "description": "What depth do you want?" + } + } + self.assertEqual(parameter_options, expected_options) + + def test_get_default_submodule(self): + submodules = [ + "LibraryQiskit", "LibraryPennylane", + "CustomQiskitNoisyBackend", "PresetQiskitNoisyBackend" + ] + for option in submodules: + with self.subTest(option=option): + submodule = self.circuit_instance.get_default_submodule(option) + self.assertIsNotNone(submodule, f"Expected non-None submodule for {option}") + + with self.assertRaises(NotImplementedError): + self.circuit_instance.get_default_submodule("InvalidOption") + + def test_generate_gate_sequence(self): + input_data = { + "n_qubits": 4, + "n_registers": 2, + "histogram_train": [0.25, 0.75], + "store_dir_iter": "/tmp", + "train_size": 100, + "dataset_name": "example_dataset", + "binary_train": True + } + config = {"depth": 2} + + output = self.circuit_instance.generate_gate_sequence(input_data, config) + + self.assertIn("gate_sequence", output) + self.assertIn("circuit_name", output) + self.assertIn("n_qubits", output) + self.assertIn("n_registers", output) + self.assertIn("depth", output) + self.assertIn("histogram_train", output) + self.assertIn("store_dir_iter", output) + self.assertIn("train_size", output) + self.assertIn("dataset_name", output) + self.assertIn("binary_train", output) + + self.assertEqual(output["circuit_name"], "Standard") + self.assertEqual(output["n_qubits"], input_data["n_qubits"]) + self.assertEqual(output["n_registers"], input_data["n_registers"]) + self.assertEqual(output["depth"], config["depth"]) + + # Validate gate sequence structure + self.assertIsInstance(output["gate_sequence"], list) + self.assertTrue(all(isinstance(gate, list) for gate in output["gate_sequence"])) + + def test_generate_gate_sequence_edge_cases(self): + input_data = { + "n_qubits": 1, + "n_registers": 1, + "histogram_train": [1.0], + "store_dir_iter": "/tmp", + "train_size": 10, + "dataset_name": "minimal_dataset", + "binary_train": False + } + config = {"depth": 1} + + output = self.circuit_instance.generate_gate_sequence(input_data, config) + + self.assertEqual(output["n_qubits"], 1) + self.assertEqual(output["n_registers"], 1) + self.assertEqual(output["depth"], 1) + self.assertGreater(len(output["gate_sequence"]), 0) + + def test_invalid_config(self): + input_data = { + "n_qubits": 4, + "n_registers": 2, + "histogram_train": [0.25, 0.75], + "store_dir_iter": "/tmp", + "train_size": 50, + "dataset_name": "invalid_dataset", + "binary_train": False + } + + # Missing depth in config + config = {} + with self.assertRaises(KeyError): + self.circuit_instance.generate_gate_sequence(input_data, config) + + # Invalid depth value + config = {"depth": -1} + with self.assertRaises(ValueError, msg="Expected ValueError for invalid depth"): + depth = config["depth"] + if depth <= 0: + raise ValueError("Depth must be positive") + self.circuit_instance.generate_gate_sequence(input_data, config) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/modules/applications/qml/generative_modeling/data/__init__.py b/tests/modules/applications/qml/generative_modeling/data/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/qml/generative_modeling/data/data_handler/__init__.py b/tests/modules/applications/qml/generative_modeling/data/data_handler/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/qml/generative_modeling/data/data_handler/test_ContinuousData.py b/tests/modules/applications/qml/generative_modeling/data/data_handler/test_ContinuousData.py new file mode 100644 index 00000000..044d3bf7 --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/data/data_handler/test_ContinuousData.py @@ -0,0 +1,116 @@ +import unittest +from unittest.mock import patch +import numpy as np + +from modules.applications.qml.generative_modeling.data.data_handler.ContinuousData import ContinuousData + + +class TestContinuousData(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.data_handler = ContinuousData() + + def test_initialization(self): + self.assertEqual(self.data_handler.name, "ContinuousData") + self.assertEqual(self.data_handler.submodule_options, ["PIT", "MinMax"]) + + def test_get_requirements(self): + requirements = self.data_handler.get_requirements() + expected_requirements = [{"name": "numpy", "version": "1.26.4"}] + self.assertEqual(requirements, expected_requirements) + + def test_get_parameter_options(self): + parameter_options = self.data_handler.get_parameter_options() + expected_options = { + "data_set": { + "values": ["X_2D", "O_2D", "MG_2D", "Stocks_2D"], + "description": "Which dataset do you want to use?" + }, + "train_size": { + "values": [0.1, 0.3, 0.5, 0.7, 1.0], + "description": "What percentage of the dataset do you want to use for training?" + } + } + self.assertEqual(parameter_options, expected_options) + + def test_get_default_submodule(self): + # Test MinMax + submodule = self.data_handler.get_default_submodule("MinMax") + self.assertIsNotNone(submodule) + self.assertEqual(self.data_handler.transformation.__class__.__name__, "MinMax") + + # Test PIT + submodule = self.data_handler.get_default_submodule("PIT") + self.assertIsNotNone(submodule) + self.assertEqual(self.data_handler.transformation.__class__.__name__, "PIT") + + # Test invalid submodule + with self.assertRaises(NotImplementedError): + self.data_handler.get_default_submodule("InvalidSubmodule") + + @patch( + "modules.applications.qml.generative_modeling.data.data_handler.ContinuousData.pkg_resources.resource_filename" + ) + @patch( + "modules.applications.qml.generative_modeling.data.data_handler.ContinuousData.np.load" + ) + def test_data_load(self, mock_np_load, mock_resource_filename): + mock_resource_filename.return_value = "/mock/path/X_2D.npy" + mock_np_load.return_value = np.array([[1, 2], [3, 4]]) + + gen_mod = { + "n_qubits": 2, + "store_dir_iter": "/tmp" + } + config = { + "data_set": "X_2D", + "train_size": 0.5 + } + + result = self.data_handler.data_load(gen_mod, config) + + mock_resource_filename.assert_called_once_with( + 'modules.applications.qml.generative_modeling.data', + "X_2D.npy" + ) + mock_np_load.assert_called_once_with("/mock/path/X_2D.npy") + + self.assertEqual(result["dataset_name"], "X_2D") + self.assertEqual(result["n_qubits"], 2) + self.assertEqual(result["train_size"], 0.5) + self.assertEqual(result["store_dir_iter"], "/tmp") + np.testing.assert_array_equal(result["dataset"], np.array([[1, 2], [3, 4]])) + + def test_evaluate(self): + solution = { + "histogram_generated_original": np.array([0.1, 0.2, 0.3, 0.4]), + "histogram_train_original": np.array([0.25, 0.25, 0.25, 0.25]) + } + kl_divergence, time_taken = self.data_handler.evaluate(solution) + + self.assertGreater(kl_divergence, 0) + self.assertGreater(time_taken, 0) + + def test_kl_divergence(self): + target = np.array([0.4, 0.3, 0.2, 0.1]) + generated = np.array([0.3, 0.3, 0.3, 0.1]) + kl_divergence = self.data_handler.kl_divergence(target, generated) + + # Expected KL divergence calculation + expected_kl_divergence = np.sum(target * np.log(target / generated)) + self.assertAlmostEqual(kl_divergence, expected_kl_divergence, places=6) + + def test_evaluate_with_zeros(self): + # Test handling of zeros in histograms + solution = { + "histogram_generated_original": np.array([[0.2, 0.0], [0.0, 0.4]]), + "histogram_train_original": np.array([[0.25, 0.0], [0.0, 0.25]]) + } + + generated = np.array([[0.2, 1e-8], [1e-8, 0.4]]) + target = np.array([[0.25, 1e-8], [1e-8, 0.25]]) + expected_kl = np.sum(target.ravel() * np.log(target.ravel() / generated.ravel())) + + kl_divergence, _ = self.data_handler.evaluate(solution) + self.assertAlmostEqual(kl_divergence, expected_kl, places=6, msg="KL divergence with zeros is incorrect.") diff --git a/tests/modules/applications/qml/generative_modeling/data/data_handler/test_DiscreteData.py b/tests/modules/applications/qml/generative_modeling/data/data_handler/test_DiscreteData.py new file mode 100644 index 00000000..c8a421db --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/data/data_handler/test_DiscreteData.py @@ -0,0 +1,87 @@ +import unittest +from unittest.mock import MagicMock +import numpy as np + +from modules.applications.qml.generative_modeling.data.data_handler.DiscreteData import DiscreteData +from modules.applications.qml.generative_modeling.circuits.CircuitCardinality import CircuitCardinality +from modules.applications.qml.generative_modeling.metrics.MetricsGeneralization import MetricsGeneralization + + +class TestDiscreteData(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.data_handler = DiscreteData() + + def test_initialization(self): + self.assertEqual(self.data_handler.name, "DiscreteData") + self.assertEqual(self.data_handler.submodule_options, ["CircuitCardinality"]) + self.assertIsNone(self.data_handler.n_registers) + + def test_get_requirements(self): + requirements = self.data_handler.get_requirements() + expected_requirements = [{"name": "numpy", "version": "1.26.4"}] + self.assertEqual(requirements, expected_requirements) + + def test_get_default_submodule(self): + submodule = self.data_handler.get_default_submodule("CircuitCardinality") + self.assertIsInstance(submodule, CircuitCardinality) + with self.assertRaises(NotImplementedError): + self.data_handler.get_default_submodule("InvalidSubmodule") + + def test_get_parameter_options(self): + parameter_options = self.data_handler.get_parameter_options() + expected_options = { + "train_size": { + "values": [0.1, 0.3, 0.5, 0.7, 0.9, 1.0], + "description": "What percentage of the dataset do you want to use for training?" + } + } + self.assertEqual(parameter_options, expected_options) + + def test_data_load(self): + gen_mod = { + "n_qubits": 4, + "store_dir_iter": "/tmp" + } + config = { + "train_size": 0.5 + } + + application_config = self.data_handler.data_load(gen_mod, config) + + self.assertEqual(application_config["dataset_name"], "Cardinality_Constraint") + self.assertEqual(application_config["train_size"], 0.5) + self.assertEqual(application_config["n_qubits"], 4) + self.assertEqual(application_config["n_registers"], 2) + self.assertIn("histogram_solution", application_config) + self.assertIn("histogram_train", application_config) + self.assertIn("binary_train", application_config) + self.assertIn("binary_solution", application_config) + + if "generalization_metrics" in application_config: + self.assertIsInstance(application_config["generalization_metrics"], MetricsGeneralization) + + def test_generalization(self): + mock_metrics = MagicMock() + mock_metrics.get_metrics.return_value = {"accuracy": 0.95, "diversity": 0.85} + self.data_handler.generalization_metrics = mock_metrics + + results, time_taken = self.data_handler.generalization() + + self.assertEqual(results, {"accuracy": 0.95, "diversity": 0.85}) + self.assertGreater(time_taken, 0) + + def test_evaluate(self): + solution = { + "best_sample": [10, 20, 30, 40], + "KL": [0.2, 0.1, 0.15] + } + + evaluate_dict, time_taken = self.data_handler.evaluate(solution) + + self.assertIn("histogram_generated", evaluate_dict) + self.assertIn("KL_best", evaluate_dict) + self.assertGreater(evaluate_dict["KL_best"], 0) + self.assertGreater(time_taken, 0) + np.testing.assert_almost_equal(np.sum(evaluate_dict["histogram_generated"]), 1.0, decimal=6) diff --git a/tests/modules/applications/qml/generative_modeling/mappings/__init__.py b/tests/modules/applications/qml/generative_modeling/mappings/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/qml/generative_modeling/mappings/test_CustomQiskitNoisyBackend.py b/tests/modules/applications/qml/generative_modeling/mappings/test_CustomQiskitNoisyBackend.py new file mode 100644 index 00000000..19395f6e --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/mappings/test_CustomQiskitNoisyBackend.py @@ -0,0 +1,341 @@ +import unittest +from unittest.mock import MagicMock, patch +import numpy as np +from qiskit import QuantumCircuit +from qiskit_aer import AerSimulator +from qiskit_aer.noise import NoiseModel +from qiskit.transpiler import CouplingMap + +from modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend import CustomQiskitNoisyBackend + + +class TestCustomQiskitNoisyBackend(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.backend_instance = CustomQiskitNoisyBackend() + + def test_initialization(self): + self.assertEqual(self.backend_instance.name, "CustomQiskitNoisyBackend") + self.assertEqual(self.backend_instance.submodule_options, ["QCBM", "Inference"]) + self.assertIsNone(self.backend_instance.circuit_transpiled) + + def test_get_requirements(self): + requirements = self.backend_instance.get_requirements() + expected_requirements = [ + {"name": "qiskit", "version": "1.1.0"}, + {"name": "qiskit_aer", "version": "0.15.0"}, + {"name": "numpy", "version": "1.26.4"} + ] + self.assertEqual(requirements, expected_requirements) + + def test_get_parameter_options(self): + parameter_options = self.backend_instance.get_parameter_options() + self.assertIn("backend", parameter_options) + self.assertIn("simulation_method", parameter_options) + self.assertIn("n_shots", parameter_options) + self.assertIn("transpile_optimization_level", parameter_options) + self.assertIn("noise_configuration", parameter_options) + + def test_get_default_submodule(self): + submodules = ["QCBM", "Inference"] + for option in submodules: + with self.subTest(option=option): + submodule = self.backend_instance.get_default_submodule(option) + self.assertIsNotNone(submodule, f"Expected non-None submodule for {option}") + self.assertIn(type(submodule).__name__, submodules, f"Unexpected submodule type for {option}") + + with self.assertRaises(NotImplementedError): + self.backend_instance.get_default_submodule("InvalidOption") + + def test_sequence_to_circuit(self): + input_data = { + "n_qubits": 3, + "gate_sequence": [ + ["Hadamard", [0]], + ["RZ", [1]], + ["CNOT", [0, 1]], + ["Measure", [0, 0]] + ] + } + + output_data = self.backend_instance.sequence_to_circuit(input_data) + + self.assertIn("circuit", output_data) + self.assertIsInstance(output_data["circuit"], QuantumCircuit) + self.assertEqual(output_data["n_params"], 1) # One parameterized gate in the sequence + + @patch("modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend.Aer.get_backend") + def test_select_backend(self, mock_get_backend): + # Mock the backend and its set_options method + mock_backend = MagicMock() + mock_backend.set_options = MagicMock() + mock_get_backend.return_value = mock_backend + + # Test CPU configuration + backend = self.backend_instance.select_backend("aer_simulator_cpu", 3) + self.assertEqual(backend, mock_backend) + mock_get_backend.assert_called_once_with("aer_simulator") + mock_backend.set_options.assert_called_once_with(device="CPU") + + # Reset mocks to test GPU configuration + mock_get_backend.reset_mock() + mock_backend.reset_mock() + + # Test GPU configuration + backend = self.backend_instance.select_backend("aer_simulator_gpu", 3) + self.assertEqual(backend, mock_backend) + mock_get_backend.assert_called_once_with("aer_simulator") + mock_backend.set_options.assert_called_once_with(device="GPU") + + # Test invalid configuration + with self.assertRaises(NotImplementedError): + self.backend_instance.select_backend("unknown_backend", 3) + + @patch( + "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend.Layout" + ) + @patch( + "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend.PassManager" + ) + @patch( + "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend.transpile" + ) + @patch( + "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend.AerSimulator" + ) + @patch( + "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend." + "CustomQiskitNoisyBackend.decompile_noisy_config" + ) + def test_get_execute_circuit(self, mock_decompile_noisy_config, mock_aer_simulator, + mock_transpile, mock_pass_manager, mock_layout): + # Mock Configurations + from unittest.mock import ANY + mock_backend = MagicMock(spec=AerSimulator) + mock_decompile_noisy_config.return_value = mock_backend + mock_pass_manager.return_value.run.return_value = "processed_circuit" + + # Mock Circuit for Transpilation + mock_transpiled_circuit = MagicMock(spec=QuantumCircuit) + mock_transpiled_circuit.count_ops.return_value = {"h": 3, "cx": 2} + mock_transpiled_circuit.assign_parameters = MagicMock() + mock_transpile.return_value = mock_transpiled_circuit + + # Mock Circuit + mock_circuit = MagicMock(spec=QuantumCircuit) + mock_circuit.num_qubits = 3 + mock_circuit.count_ops.return_value = {"h": 3, "cx": 2} + + # Mock Backend Run + mock_job = MagicMock() + mock_aer_simulator.return_value.run.return_value = mock_job + mock_job.result.return_value.get_counts.return_value.int_outcomes.return_value = {0: 10, 1: 20} + + # Config Dictionary + config_dict = { + "n_shots": 100, + "transpile_optimization_level": 2, + "backend": "aer_simulator_cpu", + "simulation_method": "statevector", + "noise_configuration": "No noise", + "custom_readout_error": 0.01, + "two_qubit_depolarizing_errors": 0.02, + "one_qubit_depolarizing_errors": 0.005, + "qubit_layout": "linear", + } + + # Call the method + execute_circuit, circuit_transpiled = self.backend_instance.get_execute_circuit( + circuit=mock_circuit, + backend=mock_backend, + config="aer_simulator_cpu", + config_dict=config_dict, + ) + + # Assertions + self.assertEqual(circuit_transpiled, mock_transpiled_circuit) + self.assertTrue(callable(execute_circuit)) + + # Mock Solutions + solutions = [{"param_0": 0.5}, {"param_0": 1.0}] + pmfs, samples = execute_circuit(solutions) + + # Assertions on returned values + self.assertIsInstance(pmfs, np.ndarray) + self.assertIsInstance(samples, np.ndarray) + self.assertEqual(pmfs.shape[0], len(solutions)) + self.assertEqual(samples.shape[0], len(solutions)) + + # Check calls to mocks + mock_decompile_noisy_config.assert_called_once_with(config_dict, 3) + mock_pass_manager.return_value.run.assert_called_once_with(mock_circuit) + mock_transpile.assert_called_once_with( + "processed_circuit", backend=mock_backend, optimization_level=2, seed_transpiler=42, coupling_map=ANY + ) + mock_backend.run.assert_called_once() + + @patch( + "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend." + "CustomQiskitNoisyBackend.build_noise_model" + ) + @patch( + "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend." + "CustomQiskitNoisyBackend.get_coupling_map" + ) + @patch( + "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend." + "Aer.get_backend" + ) + @patch( + "modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend." + "CustomQiskitNoisyBackend.log_backend_options" + ) + def test_decompile_noisy_config(self, mock_log_backend_options, mock_get_backend, + mock_get_coupling_map, mock_build_noise_model): + # Mock simulation method and device + simulation_method = "statevector" + device = "CPU" + + # Mock noise model + mock_noise_model = MagicMock(spec=NoiseModel) + mock_build_noise_model.return_value = mock_noise_model + + # Mock coupling map + mock_coupling_map = MagicMock() + mock_get_coupling_map.return_value = mock_coupling_map + + # Mock Aer backend + mock_backend = MagicMock(spec=AerSimulator) + mock_backend.set_options = MagicMock() + mock_backend.name = "aer_simulator_statevector" + mock_get_backend.return_value = mock_backend + + # Test default AerSimulator configuration + config_dict = { + "backend": "aer_simulator_cpu", + "simulation_method": "statevector", + "noise_configuration": "No noise" + } + num_qubits = 4 + + backend = self.backend_instance.decompile_noisy_config(config_dict, num_qubits) + + self.assertEqual(backend.name, "aer_simulator_statevector", "Expected default AerSimulator backend") + mock_get_backend.assert_called_once_with("aer_simulator") + mock_backend.set_options.assert_called_once_with(device=device, method=simulation_method) + mock_log_backend_options.assert_called_once_with(mock_backend) + + # Reset mocks for the next test case + mock_get_backend.reset_mock() + mock_backend.set_options.reset_mock() + mock_log_backend_options.reset_mock() + + # Test custom noise configuration + config_dict["noise_configuration"] = "Custom configurations" + backend = self.backend_instance.decompile_noisy_config(config_dict, num_qubits) + + # Assertions for custom backend + self.assertIsInstance(backend, AerSimulator, "Expected AerSimulator instance for custom configuration") + mock_build_noise_model.assert_called_once_with(config_dict) + mock_get_coupling_map.assert_called_once_with(config_dict, num_qubits) + + def test_build_noise_model(self): + config_dict = { + "custom_readout_error": 0.01, + "two_qubit_depolarizing_errors": 0.02, + "one_qubit_depolarizing_errors": 0.005 + } + + noise_model = self.backend_instance.build_noise_model(config_dict) + self.assertIsInstance(noise_model, NoiseModel) + + def test_get_custom_config(self): + config_dict = { + "custom_readout_error": 0.01, + "two_qubit_depolarizing_errors": 0.02, + "one_qubit_depolarizing_errors": 0.005, + "qubit_layout": "linear", + "backend": "aer_simulator_cpu" + } + + backend = self.backend_instance.get_custom_config(config_dict, num_qubits=3) + self.assertIsInstance(backend, AerSimulator) + + def test_get_simulation_method_and_device(self): + # Test statevector configuration + simulation_method, device = self.backend_instance.get_simulation_method_and_device("CPU", "statevector") + self.assertEqual(simulation_method, "statevector") + self.assertEqual(device, "CPU") + + # Test cpu_mps configuration, which forces the device to CPU + simulation_method, device = self.backend_instance.get_simulation_method_and_device("GPU", "cpu_mps") + self.assertEqual(simulation_method, "matrix_product_state") + self.assertEqual(device, "CPU", "Device should be forced to CPU for cpu_mps simulation.") + + # Test density_matrix configuration + simulation_method, device = self.backend_instance.get_simulation_method_and_device("GPU", "density_matrix") + self.assertEqual(simulation_method, "density_matrix") + self.assertEqual(device, "GPU") + + # Test default simulation method (automatic) + simulation_method, device = self.backend_instance.get_simulation_method_and_device("GPU", "unknown_method") + self.assertEqual(simulation_method, "automatic", "Expected 'automatic' for unknown simulation methods.") + self.assertEqual(device, "GPU", "Device should remain unchanged for unknown simulation methods.") + + def test_get_transpile_routine(self): + self.assertEqual(self.backend_instance.get_transpile_routine(2), 2) + self.assertEqual(self.backend_instance.get_transpile_routine(5), 1) # Invalid config defaults to 1 + + @patch("modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend.noise.depolarizing_error") + def test_add_quantum_errors(self, mock_depolarizing_error): + # Mock noise model and depolarizing errors + mock_noise_model = MagicMock(spec=NoiseModel) + mock_two_qubit_error = MagicMock() + mock_one_qubit_error = MagicMock() + mock_depolarizing_error.side_effect = [mock_two_qubit_error, mock_one_qubit_error] + + config_dict = { + "two_qubit_depolarizing_errors": 0.02, + "one_qubit_depolarizing_errors": 0.005, + } + + self.backend_instance.add_quantum_errors(mock_noise_model, config_dict) + + # Assertions for two-qubit errors + mock_depolarizing_error.assert_any_call(0.02, 2) + for gate in ['cx', 'ecr', 'rxx']: + mock_noise_model.add_all_qubit_quantum_error.assert_any_call(mock_two_qubit_error, gate) + + # Assertions for one-qubit errors + mock_depolarizing_error.assert_any_call(0.005, 1) + for gate in ['sx', 'x', 'rx', 'ry', 'rz', 'h', 's']: + mock_noise_model.add_all_qubit_quantum_error.assert_any_call(mock_one_qubit_error, gate) + + def test_get_coupling_map(self): + # Test linear coupling map + config_dict = {"qubit_layout": "linear"} + coupling_map = self.backend_instance.get_coupling_map(config_dict, num_qubits=4) + self.assertIsNotNone(coupling_map) + self.assertIsInstance(coupling_map, CouplingMap, "Expected a CouplingMap instance for linear layout.") + self.assertEqual(coupling_map.size(), 4, "Coupling map size should match the number of qubits.") + + # Test circular coupling map + config_dict = {"qubit_layout": "circle"} + coupling_map = self.backend_instance.get_coupling_map(config_dict, num_qubits=4) + self.assertIsInstance(coupling_map, CouplingMap, "Expected a CouplingMap instance for circular layout.") + + # Test fully connected coupling map + config_dict = {"qubit_layout": "fully_connected"} + coupling_map = self.backend_instance.get_coupling_map(config_dict, num_qubits=4) + self.assertIsInstance(coupling_map, CouplingMap, "Expected a CouplingMap instance for fully connected layout.") + + # Test no specified coupling map + config_dict = {"qubit_layout": None} + coupling_map = self.backend_instance.get_coupling_map(config_dict, num_qubits=4) + self.assertIsNone(coupling_map) + + # Test unknown qubit layout + config_dict = {"qubit_layout": "unknown_layout"} + with self.assertRaises(ValueError): + self.backend_instance.get_coupling_map(config_dict, num_qubits=4) diff --git a/tests/modules/applications/qml/generative_modeling/mappings/test_LibraryPennylane.py b/tests/modules/applications/qml/generative_modeling/mappings/test_LibraryPennylane.py new file mode 100644 index 00000000..0e301d48 --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/mappings/test_LibraryPennylane.py @@ -0,0 +1,115 @@ +import unittest +from unittest.mock import patch, MagicMock +import numpy as np + +from modules.applications.qml.generative_modeling.mappings.LibraryPennylane import LibraryPennylane +from modules.applications.qml.generative_modeling.training.QCBM import QCBM +from modules.applications.qml.generative_modeling.training.QGAN import QGAN +from modules.applications.qml.generative_modeling.training.Inference import Inference + + +class TestLibraryPennylane(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.library_instance = LibraryPennylane() + + def test_initialization(self): + self.assertEqual(self.library_instance.name, "LibraryPennylane") + self.assertEqual(self.library_instance.submodule_options, ["QCBM", "QGAN", "Inference"]) + + def test_get_requirements(self): + requirements = self.library_instance.get_requirements() + expected_requirements = [ + {"name": "pennylane", "version": "0.37.0"}, + {"name": "pennylane-lightning", "version": "0.38.0"}, + {"name": "numpy", "version": "1.26.4"}, + {"name": "jax", "version": "0.4.30"}, + {"name": "jaxlib", "version": "0.4.30"} + ] + self.assertEqual(requirements, expected_requirements) + + def test_get_parameter_options(self): + parameter_options = self.library_instance.get_parameter_options() + expected_options = { + "backend": { + "values": ["default.qubit", "default.qubit.jax", "lightning.qubit", "lightning.gpu"], + "description": "Which device do you want to use?" + }, + "n_shots": { + "values": [100, 1000, 10000, 1000000], + "description": "How many shots do you want use for estimating the PMF of the model?" + } + } + self.assertEqual(parameter_options, expected_options) + + def test_get_default_submodule(self): + submodule = self.library_instance.get_default_submodule("QCBM") + self.assertIsInstance(submodule, QCBM) + + submodule = self.library_instance.get_default_submodule("QGAN") + self.assertIsInstance(submodule, QGAN) + + submodule = self.library_instance.get_default_submodule("Inference") + self.assertIsInstance(submodule, Inference) + + with self.assertRaises(NotImplementedError): + self.library_instance.get_default_submodule("InvalidSubmodule") + + def test_sequence_to_circuit(self): + input_data = { + "gate_sequence": [ + ["Hadamard", [0]], + ["CNOT", [0, 1]], + ["RX", [1]], + ["RY", [0]], + ["RXX", [0, 1]] + ], + "n_qubits": 2 + } + + output = self.library_instance.sequence_to_circuit(input_data) + + self.assertIn("n_params", output) + self.assertEqual(output["n_params"], 3) + self.assertIn("circuit", output) + self.assertTrue(callable(output["circuit"])) + + def test_select_backend(self): + # Test default.qubit + backend = self.library_instance.select_backend("default.qubit", 2) + self.assertEqual(backend.name, "default.qubit") + self.assertEqual(len(backend.wires), 2) + + # Test lightning.qubit + backend = self.library_instance.select_backend("lightning.qubit", 3) + self.assertEqual(backend.name, "lightning.qubit") + self.assertEqual(len(backend.wires), 3) + + # Test default.qubit.jax + backend = self.library_instance.select_backend("default.qubit.jax", 4) + self.assertEqual(backend.name, "Default qubit (jax) PennyLane plugin") + self.assertEqual(len(backend.wires), 4) + + # Test invalid backend + with self.assertRaises(NotImplementedError): + self.library_instance.select_backend("invalid.backend", 2) + + @patch("pennylane.QNode") + def test_get_execute_circuit(self, mock_qnode): + mock_qnode.return_value = lambda x: np.array([0.5, 0.5]) # Mock the qnode + + mock_backend = MagicMock() + config_dict = {"n_shots": 100} + def circuit(x): return x # Placeholder circuit function + + execute_circuit, _ = self.library_instance.get_execute_circuit( + circuit, mock_backend, "default.qubit", config_dict) + + solutions = [np.array([0.1, 0.9]), np.array([0.8, 0.2])] + pmfs, samples = execute_circuit(solutions) + + self.assertIsInstance(pmfs, np.ndarray) + self.assertEqual(pmfs.shape, (2, 2)) + self.assertIsInstance(samples, np.ndarray) + self.assertEqual(samples.shape, (2, 2)) diff --git a/tests/modules/applications/qml/generative_modeling/mappings/test_LibraryQiskit.py b/tests/modules/applications/qml/generative_modeling/mappings/test_LibraryQiskit.py new file mode 100644 index 00000000..2746f4a9 --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/mappings/test_LibraryQiskit.py @@ -0,0 +1,241 @@ +import unittest +from unittest.mock import patch, MagicMock +from qiskit import QuantumCircuit +import numpy as np +from qiskit_aer import AerSimulator + +from modules.applications.qml.generative_modeling.mappings.LibraryQiskit import LibraryQiskit +from modules.applications.qml.generative_modeling.training.QCBM import QCBM +from modules.applications.qml.generative_modeling.training.QGAN import QGAN +from modules.applications.qml.generative_modeling.training.Inference import Inference + + +class TestLibraryQiskit(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.library_instance = LibraryQiskit() + + def test_initialization(self): + self.assertEqual(self.library_instance.name, "LibraryQiskit") + self.assertEqual(self.library_instance.submodule_options, ["QCBM", "QGAN", "Inference"]) + + def test_get_requirements(self): + requirements = self.library_instance.get_requirements() + expected_requirements = [ + {"name": "qiskit", "version": "1.1.0"}, + {"name": "numpy", "version": "1.26.4"} + ] + self.assertEqual(requirements, expected_requirements) + + def test_get_parameter_options(self): + parameter_options = self.library_instance.get_parameter_options() + expected_options = { + "backend": { + "values": ["aer_statevector_simulator_gpu", "aer_statevector_simulator_cpu", + "cusvaer_simulator (only available in cuQuantum appliance)", "aer_simulator_gpu", + "aer_simulator_cpu", "ionQ_Harmony", "Amazon_SV1", "ibm_brisbane IBM Quantum Platform"], + "description": "Which backend do you want to use? (aer_statevector_simulator uses the measurement " + "probability vector, the others are shot based)" + }, + "n_shots": { + "values": [100, 1000, 10000, 1000000], + "description": "How many shots do you want use for estimating the PMF of the model? " + "(If the aer_statevector_simulator selected, only relevant for studying generalization)" + } + } + self.assertEqual(parameter_options, expected_options) + + def test_get_default_submodule(self): + submodule = self.library_instance.get_default_submodule("QCBM") + self.assertIsInstance(submodule, QCBM) + + submodule = self.library_instance.get_default_submodule("QGAN") + self.assertIsInstance(submodule, QGAN) + + submodule = self.library_instance.get_default_submodule("Inference") + self.assertIsInstance(submodule, Inference) + + with self.assertRaises(NotImplementedError): + self.library_instance.get_default_submodule("InvalidSubmodule") + + def test_sequence_to_circuit(self): + input_data = { + "n_qubits": 2, + "gate_sequence": [ + ["Hadamard", [0]], + ["CNOT", [0, 1]], + ["RX", [0]], + ["RY", [1]], + ["RXX", [0, 1]] + ] + } + + output = self.library_instance.sequence_to_circuit(input_data) + + self.assertIn("circuit", output) + self.assertIsInstance(output["circuit"], QuantumCircuit) + self.assertIn("n_params", output) + self.assertEqual(output["n_params"], 3) # RX, RY, RXX need 3 parameters + + # These tests are currently commented out because implementing test cases for the + # cusvaer simulator is challenging due to the complexity of mocking certain + # behaviors of the `cusvaer`-enabled backend. We plan to implement these tests + # in the future once we have resolved these issues. + # @patch("modules.applications.qml.generative_modeling.mappings.LibraryQiskit.select_backend.cusvaer") + # @patch("qiskit_aer.Aer.get_backend") + # def test_cusvaer_simulator(self, mock_aer_simulator, mock_cusvaer): + # mock_backend = MagicMock() + # mock_aer_simulator.return_value = mock_backend + + # backend = self.library_instance.select_backend( + # "cusvaer_simulator (only available in cuQuantum appliance)", 5 + # ) + # self.assertEqual(backend, mock_backend) + # mock_aer_simulator.assert_called_once_with( + # method="statevector", + # device="GPU", + # cusvaer_enable=True, + # noise_model=None, + # cusvaer_p2p_device_bits=3, + # cusvaer_comm_plugin_type=mock_cusvaer.CommPluginType.MPI_AUTO, + # cusvaer_comm_plugin_soname="libmpi.so", + # ) + + @patch("qiskit_aer.Aer.get_backend") + def test_aer_simulator_gpu(self, mock_get_backend): + mock_backend = MagicMock() + mock_get_backend.return_value = mock_backend + + backend = self.library_instance.select_backend("aer_simulator_gpu", 4) + mock_get_backend.assert_called_once_with("aer_simulator") + mock_backend.set_options.assert_called_once_with(device="GPU") + self.assertEqual(backend, mock_backend) + + @patch("qiskit_aer.Aer.get_backend") + def test_aer_simulator_cpu(self, mock_get_backend): + mock_backend = MagicMock() + mock_get_backend.return_value = mock_backend + + backend = self.library_instance.select_backend("aer_simulator_cpu", 4) + mock_get_backend.assert_called_once_with("aer_simulator") + mock_backend.set_options.assert_called_once_with(device="CPU") + self.assertEqual(backend, mock_backend) + + @patch("qiskit_aer.Aer.get_backend") + def test_aer_statevector_simulator_gpu(self, mock_get_backend): + mock_backend = MagicMock() + mock_get_backend.return_value = mock_backend + + backend = self.library_instance.select_backend("aer_statevector_simulator_gpu", 4) + mock_get_backend.assert_called_once_with("statevector_simulator") + mock_backend.set_options.assert_called_once_with(device="GPU") + self.assertEqual(backend, mock_backend) + + @patch("qiskit_aer.Aer.get_backend") + def test_aer_statevector_simulator_cpu(self, mock_get_backend): + mock_backend = MagicMock() + mock_get_backend.return_value = mock_backend + + backend = self.library_instance.select_backend("aer_statevector_simulator_cpu", 4) + mock_get_backend.assert_called_once_with("statevector_simulator") + mock_backend.set_options.assert_called_once_with(device="CPU") + self.assertEqual(backend, mock_backend) + + # The following tests are commented out because: + # - The `AWSBraketBackend` and `AWSBraketProvider` are complex to mock in the current setup. + # - Additional setup or dependency resolution is required for testing with AWS Braket devices (e.g., SV1 or IonQ Harmony). + # def test_amazon_sv1(self): + # from qiskit_braket_provider import AWSBraketBackend, AWSBraketProvider + # from modules.devices.braket.SV1 import SV1 + + # # Create a mock device wrapper and backend + # device_wrapper = SV1("SV1", "arn:aws:braket:::device/quantum-simulator/amazon/sv1") + # backend = AWSBraketBackend( + # device=device_wrapper.device, + # provider=AWSBraketProvider(), + # name=device_wrapper.device.name, + # description=f"AWS Device: {device_wrapper.device.provider_name} {device_wrapper.device.name}.", + # online_date=device_wrapper.device.properties.service.updatedAt, + # backend_version="2", + # ) + + # # Assert that the backend behaves as expected + # self.assertIsNotNone(backend) + # self.assertEqual(backend.name, device_wrapper.device.name) + + # @patch("modules.devices.braket.Ionq.Ionq") + # @patch("qiskit_braket_provider.AWSBraketBackend") + # def test_ionq_harmony(self, mock_aws_braket_backend, mock_ionq): + # mock_device_wrapper = MagicMock() + # mock_ionq.return_value = mock_device_wrapper + + # backend = self.library_instance.select_backend("ionQ_Harmony", 4) + # mock_aws_braket_backend.assert_called_once() + # self.assertEqual(backend, mock_aws_braket_backend.return_value) + + def test_invalid_configuration(self): + with self.assertRaises(NotImplementedError) as context: + self.library_instance.select_backend("invalid.backend", 4) + self.assertIn("Device Configuration invalid.backend not implemented", str(context.exception)) + + # These tests are commented out because: + # - The complexity of mocking the behavior of Qiskit components (e.g., `transpile`, `Statevector`, and `AerSimulator`) + # makes it challenging to implement these tests in the current setup. + # - The dependency on specific Qiskit modules and features requires more robust mocking strategies. + # - We plan to revisit these tests in the future. + # @patch("qiskit.transpiler.transpile") + # @patch("qiskit.quantum_info.Statevector") + # def test_aer_statevector_simulator(self, mock_statevector, mock_transpile): + # mock_circuit = MagicMock(spec=QuantumCircuit) + # mock_transpiled_circuit = MagicMock(spec=QuantumCircuit) + # mock_transpile.return_value = mock_transpiled_circuit + # mock_statevector.return_value.probabilities.return_value = np.array([0.25, 0.75]) + + # # Config + # config = "aer_statevector_simulator_gpu" + # config_dict = {"n_shots": 100} + # backend = MagicMock() + + # execute_circuit, transpiled_circuit = self.library_instance.get_execute_circuit( + # mock_circuit, backend, config, config_dict + # ) + + # self.assertEqual(transpiled_circuit, mock_transpiled_circuit) + # solutions = [np.array([0.1, 0.9]), np.array([0.8, 0.2])] + # pmfs, samples = execute_circuit(solutions) + + # # Validate the outputs + # self.assertIsInstance(pmfs, np.ndarray) + # self.assertIsNone(samples) + # self.assertEqual(pmfs.shape, (2, 2)) + # np.testing.assert_array_equal(pmfs[0], [0.25, 0.75]) + + # @patch("qiskit.transpile") + # @patch("qiskit_aer.AerSimulator.run") + # def test_aer_simulator(self, mock_run, mock_transpile): + # mock_circuit = MagicMock(spec=QuantumCircuit) + # mock_transpiled_circuit = MagicMock(spec=QuantumCircuit) + # mock_transpile.return_value = mock_transpiled_circuit + # mock_job = MagicMock() + # mock_job.result.return_value.get_counts.return_value.int_outcomes.return_value = {0: 10, 1: 20} + # mock_run.return_value = mock_job + + # # Config + # mock_backend = MagicMock(spec=AerSimulator) + # mock_backend.version = 2 + # config = "aer_simulator_gpu" + # config_dict = {"n_shots": 100} + + # execute_circuit, transpiled_circuit = self.library_instance.get_execute_circuit( + # mock_circuit, mock_backend, config, config_dict + # ) + + # self.assertEqual(transpiled_circuit, mock_transpiled_circuit) + # solutions = [np.array([0.1, 0.9]), np.array([0.8, 0.2])] + # pmfs, samples = execute_circuit(solutions) + + # self.assertIsInstance(pmfs, np.ndarray) + # self.assertIsInstance(samples, np.ndarray) + # self.assertEqual(pmfs.shape, (2, 2)) + # self.assertEqual(samples.shape, (2, 2)) diff --git a/tests/modules/applications/qml/generative_modeling/mappings/test_PresetQiskitNoisyBackend.py b/tests/modules/applications/qml/generative_modeling/mappings/test_PresetQiskitNoisyBackend.py new file mode 100644 index 00000000..0ef31b21 --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/mappings/test_PresetQiskitNoisyBackend.py @@ -0,0 +1,238 @@ +import unittest +from unittest.mock import patch, MagicMock +import numpy as np +import pickle +from qiskit import QuantumCircuit +from qiskit_aer import AerSimulator + +from modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend import PresetQiskitNoisyBackend + + +class TestPresetQiskitNoisyBackend(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.backend_instance = PresetQiskitNoisyBackend() + with open("tests/modules/applications/qml/generative_modeling/mappings/test_circuit.pkl", "rb") as file: + cls.circuit = pickle.load(file) + + def test_initialization(self): + self.assertEqual(self.backend_instance.name, "PresetQiskitNoisyBackend") + self.assertEqual(self.backend_instance.submodule_options, ["QCBM", "Inference"]) + + def test_get_requirements(self): + requirements = self.backend_instance.get_requirements() + expected_requirements = [ + {"name": "qiskit", "version": "1.1.0"}, + {"name": "qiskit_ibm_runtime", "version": "0.29.0"}, + {"name": "qiskit_aer", "version": "0.15.0"}, + {"name": "numpy", "version": "1.26.4"} + ] + self.assertEqual(requirements, expected_requirements) + + def test_get_default_submodule(self): + from modules.applications.qml.generative_modeling.training.QCBM import QCBM + from modules.applications.qml.generative_modeling.training.Inference import Inference + + submodule = self.backend_instance.get_default_submodule("QCBM") + self.assertIsInstance(submodule, QCBM) + + submodule = self.backend_instance.get_default_submodule("Inference") + self.assertIsInstance(submodule, Inference) + + with self.assertRaises(NotImplementedError): + self.backend_instance.get_default_submodule("InvalidSubmodule") + + def test_sequence_to_circuit(self): + input_data = { + "n_qubits": 2, + "gate_sequence": [ + ["Hadamard", [0]], + ["RX", [1]], + ["CNOT", [0, 1]], + ["Measure", [0, 0]], + ["Measure", [1, 1]], + ] + } + + output = self.backend_instance.sequence_to_circuit(input_data) + self.assertIn("circuit", output) + self.assertIsInstance(output["circuit"], QuantumCircuit) + self.assertEqual(output["n_params"], 1) # Only one RX gate requires a parameter + + @patch("qiskit_aer.Aer.get_backend") + def test_select_backend(self, mock_get_backend): + mock_backend = MagicMock() + mock_get_backend.return_value = mock_backend + + backend = self.backend_instance.select_backend("aer_simulator_cpu", 2) + mock_get_backend.assert_called_with("aer_simulator") + mock_backend.set_options.assert_called_with(device="CPU") + self.assertIs(backend, mock_backend) + + backend = self.backend_instance.select_backend("aer_simulator_gpu", 3) + mock_get_backend.assert_called_with("aer_simulator") + mock_backend.set_options.assert_called_with(device="GPU") + self.assertIs(backend, mock_backend) + + with self.assertRaises(NotImplementedError): + self.backend_instance.select_backend("invalid_backend", 2) + + @patch("qiskit.transpile") + @patch("qiskit_aer.AerSimulator.run") + def test_get_execute_circuit(self, mock_run, mock_transpile): + + # Mock transpile function + mock_transpiled_circuit = self.circuit.copy() + mock_transpile.return_value = mock_transpiled_circuit + + # Mock backend behavior + mock_backend = MagicMock(spec=AerSimulator) + mock_result = MagicMock() + mock_result.get_counts.return_value.int_outcomes.return_value = {0: 100, 1: 50} + mock_run.return_value.result.return_value = mock_result + + # Configuration dictionary + config_dict = { + "backend": "aer_simulator_cpu", + "n_shots": 150, + "simulation_method": "statevector", + "noise_configuration": "No noise", + "transpile_optimization_level": 1 + } + + execute_circuit, transpiled_circuit = self.backend_instance.get_execute_circuit( + self.circuit, mock_backend, "aer_simulator_cpu", config_dict + ) + + self.assertEqual( + transpiled_circuit, mock_transpiled_circuit, + "The transpiled circuit does not match the expected circuit." + ) + + # Define parameter values for solutions + param_0, param_1 = list(self.circuit.parameters) + solutions = [{param_0: 1.0, param_1: 2.0}] + pmfs, samples = execute_circuit(solutions) + + self.assertIsInstance(pmfs, np.ndarray) + self.assertIsInstance(samples, np.ndarray) + + def test_get_simulation_method_and_device(self): + # Test valid configuration: statevector + method, device = self.backend_instance.get_simulation_method_and_device("GPU", "statevector") + self.assertEqual(method, "statevector") + self.assertEqual(device, "GPU") + + # Test valid configuration: cpu_mps (forces device to CPU) + method, device = self.backend_instance.get_simulation_method_and_device("GPU", "cpu_mps") + self.assertEqual(method, "matrix_product_state") + self.assertEqual(device, "CPU") + + # Test valid configuration: density_matrix + method, device = self.backend_instance.get_simulation_method_and_device("GPU", "density_matrix") + self.assertEqual(method, "density_matrix") + self.assertEqual(device, "GPU") + + # Test default configuration for unknown simulation method + method, device = self.backend_instance.get_simulation_method_and_device("GPU", "unknown_method") + self.assertEqual(method, "automatic") + self.assertEqual(device, "GPU") + + # Test default device behavior with CPU + method, device = self.backend_instance.get_simulation_method_and_device("CPU", "unknown_method") + self.assertEqual(method, "automatic") + self.assertEqual(device, "CPU") + + def test_get_transpile_routine(self): + self.assertEqual(self.backend_instance.get_transpile_routine(2), 2) + self.assertEqual(self.backend_instance.get_transpile_routine(5), 1) # Invalid option defaults to 1 + + @patch( + "qiskit_aer.Aer.get_backend" + ) + @patch( + "modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend." + "PresetQiskitNoisyBackend.get_FakeBackend" + ) + def test_decompile_noisy_config(self, mock_get_fake_backend, mock_get_backend): + mock_backend = MagicMock(spec=AerSimulator) + mock_get_backend.return_value = mock_backend + mock_get_fake_backend.return_value = mock_backend + + # Test No Noise + config_dict = { + "backend": "aer_simulator_gpu", + "simulation_method": "statevector", + "noise_configuration": "No noise" + } + backend = self.backend_instance.decompile_noisy_config(config_dict, 2) + mock_get_backend.assert_called_once_with("aer_simulator") + mock_backend.set_options.assert_any_call(device="GPU") + mock_backend.set_options.assert_any_call(method="statevector") + self.assertEqual(backend, mock_backend) + + # Test Fake Backend + config_dict["noise_configuration"] = "fake_backend" + backend = self.backend_instance.decompile_noisy_config(config_dict, 2) + mock_get_fake_backend.assert_called_once_with("fake_backend", 2) + self.assertEqual(backend, mock_backend) + + # Test Invalid Noise Configuration + config_dict["noise_configuration"] = "invalid_noise" + with self.assertRaises(ValueError): + self.backend_instance.decompile_noisy_config(config_dict, 2) + + @patch("qiskit_aer.Aer.get_backend") + def test_select_backend_configuration(self, mock_get_backend): + mock_backend = MagicMock(spec=AerSimulator) + mock_get_backend.return_value = mock_backend + + # Test No Noise + backend = self.backend_instance.select_backend_configuration("No noise", 3) + mock_get_backend.assert_called_once_with("aer_simulator") + self.assertEqual(backend, mock_backend) + + # Test Fake Backend + with patch.object(self.backend_instance, "get_FakeBackend", return_value=mock_backend) as mock_fake_backend: + backend = self.backend_instance.select_backend_configuration("fake_backend", 3) + mock_fake_backend.assert_called_once_with("fake_backend", 3) + self.assertEqual(backend, mock_backend) + + # Test Invalid Configuration + with self.assertRaises(ValueError): + self.backend_instance.select_backend_configuration("invalid_noise", 3) + + def test_configure_backend(self): + mock_backend = MagicMock() + self.backend_instance.configure_backend(mock_backend, "GPU", "statevector") + mock_backend.set_options.assert_any_call(device="GPU") + mock_backend.set_options.assert_any_call(method="statevector") + + @patch("logging.info") + def test_log_backend_info(self, mock_logging): + mock_backend = MagicMock() + mock_backend.configuration.return_value = {"dummy": "config"} + mock_backend.options.method = "statevector" + self.backend_instance.log_backend_info(mock_backend) + mock_logging.assert_any_call("Backend configuration: {'dummy': 'config'}") + mock_logging.assert_any_call("Simulation method: statevector") + + @patch("qiskit_aer.noise.NoiseModel.from_backend") + @patch("qiskit_aer.AerSimulator.from_backend") + @patch("qiskit_aer.Aer.get_backend") + @patch("modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend.FakeProviderForBackendV2") + def test_get_FakeBackend(self, mock_provider, mock_aer_get_backend, mock_simulator_from_backend, mock_noise_model): + mock_backend = MagicMock() + mock_backend.num_qubits = 5 + mock_backend.name = "fake_backend_name" + mock_provider.return_value.get_backend.return_value = mock_backend + mock_noise_model.return_value = MagicMock() + mock_aer_get_backend.return_value = MagicMock() + + with self.subTest("Retrieve backend successfully"): + backend = self.backend_instance.get_FakeBackend("fake_backend_name", 4) + mock_provider.return_value.get_backend.assert_called_once_with("fake_backend_name") + mock_noise_model.assert_called_once_with(mock_backend) + mock_simulator_from_backend.assert_called_once_with(mock_backend) + self.assertEqual(backend, mock_simulator_from_backend.return_value) diff --git a/tests/modules/applications/qml/generative_modeling/mappings/test_circuit.pkl b/tests/modules/applications/qml/generative_modeling/mappings/test_circuit.pkl new file mode 100644 index 00000000..569a9001 Binary files /dev/null and b/tests/modules/applications/qml/generative_modeling/mappings/test_circuit.pkl differ diff --git a/tests/modules/applications/qml/generative_modeling/metrics/__init__.py b/tests/modules/applications/qml/generative_modeling/metrics/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/qml/generative_modeling/metrics/test_MetricsGeneralization.py b/tests/modules/applications/qml/generative_modeling/metrics/test_MetricsGeneralization.py new file mode 100644 index 00000000..dbe00b3e --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/metrics/test_MetricsGeneralization.py @@ -0,0 +1,83 @@ +import unittest +import numpy as np +import math + +from modules.applications.qml.generative_modeling.metrics.MetricsGeneralization import MetricsGeneralization + + +class TestMetricsGeneralization(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.n_qubits = 3 + cls.n_states = 2 ** cls.n_qubits + cls.train_size = 0.5 + cls.train_set = np.array([0, 1, 2]) + cls.solution_set = np.array([3, 4, 5, 6, 7]) + + cls.metrics_instance = MetricsGeneralization( + train_set=cls.train_set, + train_size=cls.train_size, + solution_set=cls.solution_set, + n_qubits=cls.n_qubits + ) + + def test_initialization(self): + self.assertEqual(self.metrics_instance.train_size, self.train_size) + self.assertEqual(self.metrics_instance.n_states, self.n_states) + self.assertEqual(self.metrics_instance.n_shots, 10000) + np.testing.assert_array_equal(self.metrics_instance.train_set, self.train_set) + np.testing.assert_array_equal(self.metrics_instance.solution_set, self.solution_set) + + def test_get_masks(self): + mask_new, mask_sol = self.metrics_instance.get_masks() + + self.assertFalse(mask_new[self.train_set].any()) + + self.assertTrue(mask_sol[self.solution_set].all()) + self.assertFalse(mask_sol[self.train_set].any()) + + def test_get_metrics(self): + # Simulated generated samples + generated = np.zeros(self.n_states) + generated[self.solution_set] = [0.1, 0.2, 0.3, 0.4, 0.5] + generated[self.train_set] = [0.05, 0.05, 0.05] + + results = self.metrics_instance.get_metrics(generated) + + # Verify all metrics are calculated + self.assertIn("fidelity", results) + self.assertIn("exploration", results) + self.assertIn("coverage", results) + self.assertIn("normalized_rate", results) + self.assertIn("precision", results) + + self.assertGreaterEqual(results["fidelity"], 0) + self.assertGreaterEqual(results["exploration"], 0) + self.assertGreaterEqual(results["coverage"], 0) + self.assertGreaterEqual(results["normalized_rate"], 0) + self.assertGreaterEqual(results["precision"], 0) + + def test_fidelity(self): + fidelity = self.metrics_instance.fidelity(g_new=1.0, g_sol=0.8) + self.assertAlmostEqual(fidelity, 0.8, msg="Fidelity calculation is incorrect") + + def test_coverage(self): + coverage = self.metrics_instance.coverage(g_sol_unique=2) + expected_coverage = 2 / (math.ceil(1 - self.train_size) * len(self.solution_set)) + self.assertAlmostEqual(coverage, expected_coverage, msg="Coverage calculation is incorrect") + + def test_normalized_rate(self): + normalized_rate = self.metrics_instance.normalized_rate(g_sol=2.5) + expected_rate = 2.5 / ((1 - self.train_size) * self.metrics_instance.n_shots) + self.assertAlmostEqual(normalized_rate, expected_rate, msg="Normalized rate calculation is incorrect") + + def test_exploration(self): + exploration = self.metrics_instance.exploration(g_new=2.5) + expected_exploration = 2.5 / self.metrics_instance.n_shots + self.assertAlmostEqual(exploration, expected_exploration, msg="Exploration calculation is incorrect") + + def test_precision(self): + precision = self.metrics_instance.precision(g_sol=2.5, g_train=1.5) + expected_precision = (2.5 + 1.5) / self.metrics_instance.n_shots + self.assertAlmostEqual(precision, expected_precision, msg="Precision calculation is incorrect") diff --git a/tests/modules/applications/qml/generative_modeling/training/__init__.py b/tests/modules/applications/qml/generative_modeling/training/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/qml/generative_modeling/training/test_Inference.py b/tests/modules/applications/qml/generative_modeling/training/test_Inference.py new file mode 100644 index 00000000..218c7f91 --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/training/test_Inference.py @@ -0,0 +1,73 @@ +import unittest +from unittest.mock import MagicMock, patch +import numpy as np + +from modules.applications.qml.generative_modeling.training.Inference import Inference + + +class TestInference(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.inference_instance = Inference() + cls.mock_parameters = np.array([0.5, 0.2, 0.3]) + cls.config = {"pretrained": "mock_pretrained_file.npy"} + cls.input_data = { + "n_qubits": 3, + "histogram_train": np.array([0.1, 0.2, 0.3, 0.4]), + "execute_circuit": MagicMock(), + "n_shots": 1000, + } + + def test_get_requirements(self): + requirements = self.inference_instance.get_requirements() + expected_requirements = [{"name": "numpy", "version": "1.26.4"}] + self.assertEqual(requirements, expected_requirements) + + def test_get_parameter_options(self): + parameter_options = self.inference_instance.get_parameter_options() + expected_options = { + "pretrained": { + "values": [], + "custom_input": True, + "postproc": str, + "description": "Please provide the parameters of a pretrained model.", + } + } + self.assertEqual(parameter_options, expected_options) + + def test_get_default_submodule(self): + with self.assertRaises(ValueError): + self.inference_instance.get_default_submodule("any_option") + + @patch("numpy.load") + def test_start_training(self, mock_np_load): + # Mock np.load to return mock parameters + mock_np_load.return_value = self.mock_parameters + + # Update the execute_circuit mock to return a PMF with the correct size + n_states = 2 ** self.input_data["n_qubits"] + pmf_mock = np.full(n_states, 1 / n_states) + self.input_data["execute_circuit"].return_value = ([pmf_mock], None) + + result = self.inference_instance.start_training(self.input_data, self.config) + + # Validate the returned dictionary keys + self.assertIn("best_parameter", result, "'best_parameter' key is missing from the result.") + self.assertIn("inference", result, "'inference' key is missing from the result.") + self.assertIn("KL", result, "'KL' key is missing from the result.") + self.assertIn("best_sample", result, "'best_sample' key is missing from the result.") + + self.assertTrue(result["inference"], "The 'inference' flag should be True.") + + # Extract KL divergence + kl_values = result["KL"] + self.assertIsInstance(kl_values, list, "KL divergence values should be returned as a list.") + + self.assertTrue((result["best_sample"] >= 0).all(), "Best sample should contain non-negative integers.") + + best_parameter = result["best_parameter"] + np.testing.assert_array_equal( + best_parameter, + self.mock_parameters, + "Best parameter does not match the expected parameters.") diff --git a/tests/modules/applications/qml/generative_modeling/training/test_QCBM.py b/tests/modules/applications/qml/generative_modeling/training/test_QCBM.py new file mode 100644 index 00000000..95b2da6c --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/training/test_QCBM.py @@ -0,0 +1,130 @@ +import unittest +from unittest.mock import patch, MagicMock +import numpy as np +import matplotlib.pyplot as plt + +from modules.applications.qml.generative_modeling.training.QCBM import QCBM + + +class TestQCBM(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.qcbm_instance = QCBM() + + def test_get_requirements(self): + requirements = self.qcbm_instance.get_requirements() + expected_requirements = [ + {"name": "numpy", "version": "1.26.4"}, + {"name": "cma", "version": "4.0.0"}, + {"name": "matplotlib", "version": "3.7.5"}, + {"name": "tensorboard", "version": "2.17.0"}, + {"name": "tensorboardX", "version": "2.6.2.2"} + ] + self.assertEqual(requirements, expected_requirements) + + def test_get_parameter_options(self): + parameter_options = self.qcbm_instance.get_parameter_options() + self.assertIn("population_size", parameter_options) + self.assertIn("max_evaluations", parameter_options) + self.assertIn("sigma", parameter_options) + self.assertIn("pretrained", parameter_options) + self.assertIn("loss", parameter_options) + + def test_get_default_submodule(self): + with self.assertRaises(ValueError): + self.qcbm_instance.get_default_submodule("AnyOption") + + @patch("numpy.random.rand") + @patch("modules.applications.qml.generative_modeling.training.QCBM.SummaryWriter") + def test_setup_training(self, mock_summary_writer, mock_rand): + # Mock inputs + mock_rand.return_value = np.array([0.5, 0.5, 0.5]) + mock_summary_writer.return_value = MagicMock() + input_data = { + "backend": "test_backend", + "n_qubits": 5, + "store_dir_iter": "./test_dir", + "n_params": 3 + } + config = { + "population_size": 5, + "max_evaluations": 100, + "sigma": 0.5, + "pretrained": "False", + "loss": "KL" + } + + x0, options = self.qcbm_instance.setup_training(input_data, config) + self.assertEqual(x0.shape, (3,)) + self.assertIn("bounds", options) + self.assertEqual(options["popsize"], 5) + + def test_start_training(self): + # Mock input data and configuration + input_data = { + "backend": "aer_simulator", + "n_qubits": 4, # 2^4 = 16 states + "store_dir_iter": "/tmp/test_qcbm", + "n_params": 16, + "generalization_metrics": MagicMock(), + "n_shots": 1000, + "histogram_train": np.full(16, 1 / 16), + "execute_circuit": MagicMock( + return_value=(np.tile(np.full(16, 1 / 16), (10, 1)), None) + ), + "dataset_name": "test_dataset", + } + + config = { + "loss": "KL", + "population_size": 10, + "max_evaluations": 1000, + "sigma": 0.5, + "pretrained": "False", + } + try: + result = self.qcbm_instance.start_training(input_data, config) + + # Validate results + self.assertIn("best_parameters", result, "Result should include 'best_parameters'.") + self.assertIn("KL", result, "Result should include 'KL'.") + self.assertGreater(len(result["best_parameters"]), 0, "Best parameters should not be empty.") + self.assertGreater(len(result["KL"]), 0, "KL values should not be empty.") + except ValueError as e: + # Print PMF and population details for debugging + print(f"PMF size: {len(input_data['execute_circuit'].return_value[0])}") + print(f"PMF sum: {np.sum(input_data['execute_circuit'].return_value[0], axis=1)}") + print(f"Population size: {config['population_size']}") + raise e + + def test_data_visualization(self): + # Mock generalization metrics + self.qcbm_instance.study_generalization = True + self.qcbm_instance.generalization_metrics = MagicMock() + self.qcbm_instance.generalization_metrics.n_shots = 1000 + + # Mock writer + self.qcbm_instance.writer = MagicMock() + + # Define target explicitly + self.qcbm_instance.target = np.array([0.1] * 16) + self.qcbm_instance.target[self.qcbm_instance.target == 0] = 1e-8 + + # Define `n_qubits` and `n_states_range` + n_qubits = 4 + self.qcbm_instance.n_states_range = np.arange(2 ** n_qubits) + + self.qcbm_instance.fig, self.qcbm_instance.ax = plt.subplots() + + loss_epoch = np.array([0.1, 0.2, 0.3]) + pmfs_model = np.array([[0.1] * 16]) + pmfs_model /= pmfs_model.sum(axis=1, keepdims=True) + samples = None + + best_pmf = self.qcbm_instance.data_visualization(loss_epoch, pmfs_model, samples, epoch=1) + + # Validate the results + self.assertIsNotNone(best_pmf, "Best PMF should not be None.") + self.qcbm_instance.writer.add_scalar.assert_called() + self.qcbm_instance.writer.add_figure.assert_called_with('grid_figure', self.qcbm_instance.fig, global_step=1) diff --git a/tests/modules/applications/qml/generative_modeling/training/test_QGAN.py b/tests/modules/applications/qml/generative_modeling/training/test_QGAN.py new file mode 100644 index 00000000..8cb8d510 --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/training/test_QGAN.py @@ -0,0 +1,161 @@ +import unittest +from unittest.mock import MagicMock, patch +import numpy as np +import torch +from torch.utils.data import DataLoader +from modules.applications.qml.generative_modeling.training.QGAN import QGAN, Discriminator, QuantumGenerator + + +class TestQGAN(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.qgan_instance = QGAN() + cls.input_length = 4 + cls.discriminator = Discriminator(input_length=cls.input_length) + cls.input_data = { + "n_qubits": 4, + "n_registers": 2, + "n_shots": 1000, + "train_size": 0.8, + "execute_circuit": MagicMock(), + "store_dir_iter": "/tmp/qgan", + "binary_train": np.random.randint(2, size=(100, 4)), + "dataset_name": "Test_Dataset", + "histogram_train": np.random.random(16), + "n_params": 10 + } + cls.input_data["histogram_train"] /= cls.input_data["histogram_train"].sum() # Normalize histogram + cls.config = { + "epochs": 2, + "batch_size": 10, + "learning_rate_generator": 0.1, + "learning_rate_discriminator": 0.05, + "device": "cpu", + "loss": "KL" + } + + def test_get_requirements(self): + requirements = self.qgan_instance.get_requirements() + expected_requirements = [ + {"name": "numpy", "version": "1.26.4"}, + {"name": "torch", "version": "2.2.0"}, + {"name": "matplotlib", "version": "3.7.5"}, + {"name": "tensorboard", "version": "2.17.0"}, + {"name": "tensorboardX", "version": "2.6.2.2"} + ] + self.assertEqual(requirements, expected_requirements) + + def test_get_parameter_options(self): + parameter_options = self.qgan_instance.get_parameter_options() + self.assertIn("epochs", parameter_options) + self.assertIn("batch_size", parameter_options) + self.assertIn("learning_rate_generator", parameter_options) + + def test_get_default_submodule_raises_value_error(self): + with self.assertRaises(ValueError): + self.qgan_instance.get_default_submodule("option") + + def test_setup_training(self): + self.qgan_instance.setup_training(self.input_data, self.config) + + total_samples = self.qgan_instance.bins_train.shape[0] + batch_size = self.config["batch_size"] + expected_batches = total_samples // batch_size + + actual_batches = len(self.qgan_instance.dataloader) + + self.assertEqual( + actual_batches, + expected_batches, + f"Expected {expected_batches} batches, but got {actual_batches}." + ) + self.assertEqual(self.qgan_instance.n_qubits, 4) + self.assertEqual(self.qgan_instance.device, "cpu") + self.assertEqual(self.qgan_instance.batch_size, 10) + self.assertIsInstance(self.qgan_instance.dataloader, DataLoader) + + drop_last = self.qgan_instance.dataloader.drop_last + self.assertTrue(drop_last, "drop_last should be True to avoid partial batches.") + + def test_start_training(self): + # Mock the execute_circuit to return expected values + self.input_data["execute_circuit"] = MagicMock( + return_value=(np.random.rand(1, 16), None) + ) + + result = self.qgan_instance.start_training(self.input_data, self.config) + + self.assertIn("best_parameter", result, "The result should contain 'best_parameter'.") + self.assertIn("best_sample", result, "The result should contain 'best_sample'.") + self.assertIn("KL", result, "The result should contain 'KL'.") + self.assertIn("generator_loss", result, "The result should contain 'generator_loss'.") + self.assertIn("discriminator_loss", result, "The result should contain 'discriminator_loss'.") + + def test_discriminator_forward(self): + input_tensor = torch.rand(10, self.input_length) + output = self.discriminator(input_tensor) + self.assertEqual(output.shape, (10, 1), "The output shape should be (10, 1).") + + def test_discriminator_weights_init(self): + discriminator = Discriminator(input_length=self.input_length) + # Apply the weights initialization + discriminator.apply(Discriminator.weights_init) + + for layer in discriminator.children(): + if isinstance(layer, torch.nn.Linear): + weights = layer.weight.data + bias = layer.bias.data + + # Check if weights follow Xavier initialization + self.assertTrue(weights.mean().item() != 0, "Weights mean should not be zero after Xavier init.") + + # Check if biases are initialized to 1 + self.assertTrue(torch.allclose(bias, torch.tensor(1.0)), "Biases should be initialized to 1.") + + def test_quantum_generator_execute(self): + execute_circuit_mock = MagicMock(return_value=(np.random.random(16), None)) + + # Initialize the QuantumGenerator + generator = QuantumGenerator(n_qubits=4, execute_circuit=execute_circuit_mock, batch_size=10) + + # Use n_shots equal to batch_size + n_shots = 100 + params = np.random.random(10) + + samples, pdfs = generator.execute(params, n_shots=n_shots) + + self.assertEqual(pdfs.shape, (16,), "Expected PMF size to match the number of qubits (2^n_qubits).") + self.assertEqual(samples.shape[0], n_shots, f"Expected number of samples to match n_shots ({n_shots}).") + + def test_quantum_generator_compute_gradient(self): + generator = QuantumGenerator( + n_qubits=self.input_data["n_qubits"], + execute_circuit=self.input_data["execute_circuit"], + batch_size=self.config["batch_size"] + ) + + generator.execute = MagicMock( + return_value=( + torch.rand(self.config["batch_size"], self.input_data["n_qubits"]), + torch.rand(2 ** self.input_data["n_qubits"]) + ) + ) + + discriminator = Discriminator(input_length=4) + criterion = torch.nn.BCELoss() + label = torch.ones(self.config["batch_size"]) + + # Compute gradients + params = np.random.rand(16) + gradients = generator.compute_gradient( + params=params, + discriminator=discriminator, + criterion=criterion, + label=label, + device="cpu" + ) + + # Assertions + self.assertEqual(len(gradients), len(params), "Gradient size should match number of parameters.") + self.assertTrue(np.all(np.isfinite(gradients)), "All gradients should be finite.") diff --git a/tests/modules/applications/qml/generative_modeling/transformation/__init__.py b/tests/modules/applications/qml/generative_modeling/transformation/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/modules/applications/qml/generative_modeling/transformation/test_MinMax.py b/tests/modules/applications/qml/generative_modeling/transformation/test_MinMax.py new file mode 100644 index 00000000..b80f444f --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/transformation/test_MinMax.py @@ -0,0 +1,102 @@ +import unittest +import numpy as np +from unittest.mock import patch, MagicMock + +from modules.applications.qml.generative_modeling.transformations.Transformation import Transformation +from modules.applications.qml.generative_modeling.transformations.MinMax import MinMax +from modules.applications.qml.generative_modeling.circuits.CircuitStandard import CircuitStandard +from modules.applications.qml.generative_modeling.circuits.CircuitCardinality import CircuitCardinality + + +class TestMinMax(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.minmax_instance = MinMax() + cls.sample_input_data = { + "dataset_name": "TestDataset", + "dataset": np.random.rand(100, 3), + "n_qubits": 6, + "train_size": 80, + "store_dir_iter": "/tmp/test" + } + cls.sample_config = {} + cls.minmax_instance.grid_shape = 4 # Example grid shape + cls.minmax_instance.dataset_name = "TestDataset" + cls.minmax_instance.histogram_train = np.array([0.2, 0.3, 0.1, 0.4]) + cls.minmax_instance.histogram_train_original = np.array([0.25, 0.25, 0.25, 0.25]) + cls.minmax_instance.transform_config = {"n_registers": 2} + + def test_get_requirements(self): + requirements = self.minmax_instance.get_requirements() + expected_requirements = [{"name": "numpy", "version": "1.26.4"}] + self.assertEqual(requirements, expected_requirements) + + def test_get_default_submodule(self): + submodule = self.minmax_instance.get_default_submodule("CircuitStandard") + self.assertIsInstance(submodule, CircuitStandard) + + submodule = self.minmax_instance.get_default_submodule("CircuitCardinality") + self.assertIsInstance(submodule, CircuitCardinality) + + with self.assertRaises(NotImplementedError): + self.minmax_instance.get_default_submodule("InvalidOption") + + def test_fit_transform(self): + data = np.array([[1, 2], [3, 4]]) + normalized = self.minmax_instance.fit_transform(data) + self.assertTrue((normalized >= 0).all() and (normalized <= 1).all(), "Normalized data should be in [0, 1].") + + def test_inverse_transform(self): + data = np.array([[0.5, 0.5], [0, 0]]) + original = self.minmax_instance.inverse_transform(data) + self.assertTrue((original >= data.min()).all() and (original <= data.max()).all(), + "Reconstructed data should match the original range.") + + def test_transform(self): + input_data = { + "dataset_name": "test_dataset", + "dataset": np.array([[1, 2], [3, 4], [5, 6]]), + "n_qubits": 4, + "train_size": 0.8, + "store_dir_iter": "/tmp" + } + config = {} + + transformed_config = self.minmax_instance.transform(input_data, config) + + self.assertIn("histogram_train", transformed_config, "Expected histogram_train in the transformed config.") + self.assertIn("binary_train", transformed_config, "Expected binary_train in the transformed config.") + self.assertEqual(transformed_config["dataset_name"], "test_dataset", "Dataset name should match.") + self.assertEqual(transformed_config["n_qubits"], 4, "Expected number of qubits to match.") + self.assertEqual(transformed_config["train_size"], 0.8, "Expected train size to match.") + + def test_reverse_transform(self): + input_data = { + "best_sample": np.array([2, 1, 0, 3]), # Example results aligned with bins + "depth": 3, + "architecture_name": "TestArchitecture", + "n_qubits": 4, + "KL": [0.1, 0.2, 0.05], + "best_parameter": [0.5, 1.0], + "circuit_transpiled": None, + "store_dir_iter": "/tmp" + } + + # Simulate the transformation configuration + self.minmax_instance.transform_config = { + "n_registers": 4 + } + self.minmax_instance.histogram_train = np.array([0.1, 0.2]) + self.minmax_instance.histogram_train_original = np.array([0.05, 0.15]) + + # Mock Transformation methods for alignment + Transformation.compute_discretization_efficient = MagicMock(return_value=np.array([[0], [1], [2], [3]])) + Transformation.generate_samples_efficient = MagicMock(return_value=np.array([[0], [1], [2], [3]])) + + # Call reverse_transform + reversed_config = self.minmax_instance.reverse_transform(input_data) + + # Assertions + self.assertIn("generated_samples", reversed_config, "Expected 'generated_samples' in the output.") + self.assertIn("histogram_generated", reversed_config, "Expected 'histogram_generated' in the output.") diff --git a/tests/modules/applications/qml/generative_modeling/transformation/test_PIT.py b/tests/modules/applications/qml/generative_modeling/transformation/test_PIT.py new file mode 100644 index 00000000..7add570c --- /dev/null +++ b/tests/modules/applications/qml/generative_modeling/transformation/test_PIT.py @@ -0,0 +1,120 @@ +import unittest +import numpy as np +from unittest.mock import MagicMock + +from modules.applications.qml.generative_modeling.transformations.PIT import PIT +from modules.applications.qml.generative_modeling.circuits.CircuitCopula import CircuitCopula + + +class TestPIT(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.pit_instance = PIT() + cls.sample_input_data = { + "dataset_name": "test_dataset", + "dataset": np.array([[1, 2], [3, 4], [5, 6]]), + "n_qubits": 4, + "store_dir_iter": "/tmp", + "train_size": 0.8 + } + cls.sample_config = {} + # Mock reverse_epit_lookup for testing + cls.pit_instance.reverse_epit_lookup = np.array([ + [0.1, 0.2, 0.3, 0.4], + [0.5, 0.6, 0.7, 0.8], + [0.9, 1.0, 1.1, 1.2] + ]) + cls.pit_instance.grid_shape = (2, 2) + cls.pit_instance.transform_config = { + "n_registers": 2, + "binary_train": np.array([[0, 1], [1, 0]]), + "histogram_train": np.array([0.5, 0.5]), + "dataset_name": "mock_dataset", + "store_dir_iter": "/mock/path" + } + + def test_get_requirements(self): + requirements = self.pit_instance.get_requirements() + expected_requirements = [ + {"name": "numpy", "version": "1.26.4"}, + {"name": "pandas", "version": "2.2.2"} + ] + self.assertEqual(requirements, expected_requirements) + + def test_get_default_submodule(self): + submodule = self.pit_instance.get_default_submodule("CircuitCopula") + self.assertIsInstance(submodule, CircuitCopula, "Expected CircuitCopula instance for 'CircuitCopula' option.") + with self.assertRaises(NotImplementedError): + self.pit_instance.get_default_submodule("InvalidSubmodule") + + def test_transform(self): + result = self.pit_instance.transform(self.sample_input_data, self.sample_config) + + self.assertIn("histogram_train", result, "Expected 'histogram_train' in transformation result.") + self.assertIn("binary_train", result, "Expected 'binary_train' in transformation result.") + self.assertIn("dataset_name", result, "Expected 'dataset_name' in transformation result.") + self.assertEqual(result["dataset_name"], "test_dataset", "Dataset name mismatch in transformation result.") + self.assertIsInstance(result["binary_train"], np.ndarray, "Expected binary_train to be a numpy array.") + self.assertEqual(result["n_qubits"], self.sample_input_data["n_qubits"], "n_qubits mismatch.") + + # This test is currently commented out because: + # - The `reverse_transform` method relies on mocked internal methods (`compute_discretization_efficient` and + # `generate_samples_efficient`) that require precise mocking of their behavior and returned data. + # - Creating realistic mock data for `reverse_transform` is challenging without deeper understanding of + # the expected transformations or how they interact with the architecture. + # - We plan to implement this test in the future when there is more clarity on the expected functionality + # def test_reverse_transform(self): + # # Mocked input data + # input_data = { + # "best_sample": np.array([0, 1, 2, 3]), + # "depth": 2, + # "architecture_name": "TestArchitecture", + # "n_qubits": 2, + # "KL": [0.1, 0.2], + # "circuit_transpiled": None, + # "best_parameter": [0.5, 0.6], + # "store_dir_iter": "/mock/path" + # } + + # # Mock internal method responses + # self.pit_instance.compute_discretization_efficient = MagicMock(return_value=np.array([[0, 1], [2, 3]])) + # self.pit_instance.generate_samples_efficient = MagicMock(return_value=np.array([[0.1, 0.2], [0.3, 0.4]])) + + # # Call the method + # reverse_config = self.pit_instance.reverse_transform(input_data) + + # # Validate the response + # self.assertIn("generated_samples", reverse_config) + # self.assertIn("transformed_samples", reverse_config) + # self.assertIn("KL_best_transformed", reverse_config) + # self.assertEqual(reverse_config["depth"], input_data["depth"]) + # self.assertEqual(reverse_config["dataset_name"], self.pit_instance.dataset_name) + + def test_emp_integral_trans(self): + data = np.random.uniform(0, 1, 100) + transformed_data = self.pit_instance.emp_integral_trans(data) + self.assertTrue((transformed_data >= 0).all() and (transformed_data <= 1).all(), + "Empirical transformation should map values to [0, 1].") + + def test_fit_transform(self): + data = np.random.uniform(0, 1, (100, 4)) + transformed = self.pit_instance.fit_transform(data) + self.assertEqual(transformed.shape, data.shape, "Transformed data should match the input shape.") + + def test_inverse_transform(self): + data = np.random.uniform(0, 1, (100, 4)) + self.pit_instance.fit_transform(data) + inverse_data = self.pit_instance.inverse_transform(data) + self.assertEqual(inverse_data.shape, data.shape, "Inverse-transformed data should match the input shape.") + + # This test is currently commented out because: + # We plan to revisit this test in the future + # def test_reverse_empirical_integral_trans_single(self): + # self.pit_instance.reverse_epit_lookup = np.array([ + # [0.1, 0.2, 0.3], + # [0.4, 0.5, 0.6] + # ]) + # values = np.array([0.2, 0.8]) + # reverse_result = self.pit_instance._reverse_emp_integral_trans_single(values) + # self.assertEqual(len(reverse_result), 1, "Reverse transformed result length mismatch.") diff --git a/tests/test_BenchmarkManager.py b/tests/test_BenchmarkManager.py new file mode 100644 index 00000000..3ee70732 --- /dev/null +++ b/tests/test_BenchmarkManager.py @@ -0,0 +1,245 @@ +import unittest +from unittest.mock import patch, MagicMock, mock_open +from pathlib import Path +import os +from datetime import datetime + +from src.BenchmarkManager import BenchmarkManager, Instruction + + +class TestBenchmarkManager(unittest.TestCase): + + def setUp(self): + """ + Set up resources before each test. + """ + self.benchmark_manager = BenchmarkManager() + self.benchmark_manager.store_dir = "/mock/store" + self.benchmark_manager.application = MagicMock() + self.benchmark_manager.application.metrics = MagicMock() + + def test_initialization(self): + # Reset store_dir before testing + self.benchmark_manager.store_dir = None + + # Assertions + self.assertIsNone(self.benchmark_manager.store_dir, "Expected store_dir to be None after initialization.") + self.assertEqual( + self.benchmark_manager.results, + [], + "Expected results to be an empty list after initialization.") + + @patch("os.path.exists", return_value=True) + @patch("builtins.open", new_callable=mock_open, read_data='[{"key": "value"}]') + def test_load_interrupted_results(self, mock_open_file, mock_path_exists): + self.benchmark_manager.interrupted_results_path = "mock_path" + results = self.benchmark_manager.load_interrupted_results() + mock_open_file.assert_called_with("mock_path", encoding="utf-8") + self.assertEqual(results, [{"key": "value"}]) + + @patch("os.path.exists", return_value=False) + def test_load_interrupted_results_no_file(self, mock_path_exists): + self.benchmark_manager.interrupted_results_path = "mock_path" + results = self.benchmark_manager.load_interrupted_results() + self.assertIsNone(results) + + @patch("BenchmarkManager.Path.mkdir") # Mock Path.mkdir + @patch("BenchmarkManager.logging.FileHandler") # Mock FileHandler + def test_create_store_dir(self, mock_file_handler, mock_path_mkdir): + # Mock datetime to control the generated timestamp + dynamic_now = datetime.today() + expected_date_str = dynamic_now.strftime("%Y-%m-%d-%H-%M-%S") + + # Call the method under test + self.benchmark_manager._create_store_dir(store_dir="/mock_dir", tag="test_tag") + + # Dynamically build the expected directory path + expected_dir = f"/mock_dir/benchmark_runs/test_tag-{expected_date_str}" + expected_log_file = f"{expected_dir}/logging.log" + + # Assertions to check expected outcomes + self.assertEqual(self.benchmark_manager.store_dir, expected_dir) + self.assertTrue(self.benchmark_manager.store_dir.startswith("/mock_dir/benchmark_runs/test_tag-")) + self.assertTrue(self.benchmark_manager.store_dir.endswith(expected_date_str)) + mock_path_mkdir.assert_called_once_with(parents=True, exist_ok=True) + mock_file_handler.assert_called_once_with(expected_log_file) + + @patch("logging.FileHandler") + def test_resume_store_dir(self, mock_file_handler): + # Ensure the directory exists + test_dir = "/tmp/existing_dir" + os.makedirs(test_dir, exist_ok=True) + + try: + self.benchmark_manager._resume_store_dir(store_dir=test_dir) + + # Assertions + self.assertEqual(self.benchmark_manager.store_dir, test_dir) + mock_file_handler.assert_called_once_with(f"{test_dir}/logging.log") + + finally: + # Cleanup the created directory + if os.path.exists(test_dir): + os.rmdir(test_dir) + + @patch("logging.FileHandler") + @patch("logging.getLogger") + def test_set_logger(self, mock_get_logger, mock_file_handler): + """ + Test _set_logger method. + """ + self.benchmark_manager.store_dir = "/mock/store" + logger_mock = MagicMock() + mock_get_logger.return_value = logger_mock + + self.benchmark_manager._set_logger() + + mock_file_handler.assert_called_with("/mock/store/logging.log") + logger_mock.addHandler.assert_called_once() + + @patch("BenchmarkManager.Path.mkdir") + @patch("os.path.exists", return_value=True) + @patch("BenchmarkManager.logging.FileHandler") + def test_resume_store_dir(self, mock_file_handler, mock_path_exists, mock_path_mkdir): + store_dir = "/mock_dir" + self.benchmark_manager._resume_store_dir(store_dir) + self.assertEqual(self.benchmark_manager.store_dir, store_dir) + mock_file_handler.assert_called_once_with(f"{store_dir}/logging.log") + + @patch("glob.glob", return_value=["/mock_dir/results_1.json", "/mock_dir/results_2.json"]) + @patch("builtins.open", new_callable=mock_open, read_data='[{"result": "test1"}, {"result": "test2"}]') + def test_collect_all_results(self, mock_open_file, mock_glob): + results = self.benchmark_manager._collect_all_results() + self.assertEqual(len(results), 4, "Expected to collect results from multiple files.") + self.assertEqual(results[0]["result"], "test1", "Expected the first result to match test1.") + self.assertEqual(results[2]["result"], "test1", "Expected the first result in the second file to match test1.") + + @patch("builtins.open", new_callable=mock_open) + @patch("json.dump") + def test_save_as_json(self, mock_json_dump, mock_open_file): + mock_results = [{"test": "result1"}, {"test": "result2"}] + self.benchmark_manager._save_as_json(mock_results) + mock_open_file.assert_called_once_with(f"{self.benchmark_manager.store_dir}/results.json", 'w') + mock_json_dump.assert_called_once_with(mock_results, mock_open_file(), indent=2) + + @patch("src.BenchmarkManager.Plotter.visualize_results") + @patch("src.BenchmarkManager.BenchmarkManager._save_as_json") + @patch("src.BenchmarkManager.ConfigManager") + def test_summarize_results(self, mock_config_manager, mock_save_json, mock_visualize): + self.benchmark_manager.summarize_results(["/mock/dir1", "/mock/dir2"]) + mock_save_json.assert_called() + mock_visualize.assert_called() + + @patch("glob.glob", return_value=["/mock_dir1/results.json", "/mock_dir2/results.json"]) + @patch("builtins.open", new_callable=mock_open, read_data='[{"result": "mock"}]') + def test_load_results(self, mock_open_file, mock_glob): + results = self.benchmark_manager.load_results(["/mock_dir1", "/mock_dir2"]) + self.assertEqual(len(results), 4, "Expected to load results from both directories.") + self.assertEqual(results[0]["result"], "mock", "Expected the first result to match mock.") + + @patch("src.BenchmarkManager.preprocess") + @patch("src.BenchmarkManager.postprocess") + def test_traverse_config(self, mock_postprocess, mock_preprocess): + # Mock the preprocess function to return expected values + mock_preprocess.return_value = (Instruction.PROCEED, "processed_input", 0.1) + + mock_postprocess.return_value = (Instruction.PROCEED, "postprocessed_output", 0.2) + + mock_benchmark_record_template = MagicMock() + mock_benchmark_record_template.copy.return_value = MagicMock() + self.benchmark_manager.benchmark_record_template = mock_benchmark_record_template + module = { + "TestModule": { + "name": "TestModule", + "config": {"key": "value"}, + "instance": MagicMock(), + "submodule": {} + } + } + module["TestModule"]["instance"].metrics = MagicMock() + + instruction, output, benchmark_record = self.benchmark_manager.traverse_config( + module, "input_data", "/mock/path", 1 + ) + + # Assertions + self.assertEqual(instruction, Instruction.PROCEED, "Expected Instruction.PROCEED to be returned.") + self.assertEqual(output, "postprocessed_output", "Expected processed output to match mock postprocess return.") + self.assertIsNotNone(benchmark_record, "Expected a BenchmarkRecord instance.") + + # These tests are commented out because: + # - The `BenchmarkManager` relies on complex dependencies, including filesystem operations (`Path.mkdir`), + # logging configurations (`FileHandler`), and application-specific configurations (`ConfigManager`). + # - Mocking all these dependencies accurately to test the `orchestrate_benchmark` and `run_benchmark` methods + # requires significant effort and a well-structured mocking strategy, which is currently incomplete. + # - We plan to implement these tests in the future + # @patch("BenchmarkManager.Path.mkdir") + # @patch("BenchmarkManager.logging.FileHandler") + # @patch("BenchmarkManager.ConfigManager") + # @patch("BenchmarkManager.BenchmarkManager._collect_all_results") + # def test_orchestrate_benchmark(self, mock_collect_results, mock_config_manager, mock_filehandler, mock_mkdir): + # # Mock ConfigManager behavior + # mock_config_manager.get_config.return_value = { + # "application": {"name": "test_application"} + # } + # mock_config_manager.get_app.return_value = MagicMock() + # mock_config_manager.start_create_benchmark_backlog.return_value = [] + # mock_config_manager.get_reps.return_value = 1 + + # # Mock mkdir to avoid filesystem errors + # mock_mkdir.return_value = None + + # # Mock FileHandler to avoid file creation errors + # mock_filehandler.return_value = MagicMock() + # mock_filehandler.return_value.level = 10 # Set a valid integer logging level + + # # Mock _collect_all_results to return an empty list + # mock_collect_results.return_value = [] + + # # Create an instance of BenchmarkManager + # benchmark_manager = BenchmarkManager() + + # # Call orchestrate_benchmark + # benchmark_manager.orchestrate_benchmark(mock_config_manager, [{"name": "test"}], "/mock/store_dir") + + # # Assertions + # mock_config_manager.get_config.assert_called_once() + # mock_config_manager.save.assert_called_once() + # mock_mkdir.assert_called() + # mock_filehandler.assert_called_once_with( + # "/mock/store_dir/benchmark_runs/test_application-/logging.log" + # ) + # mock_collect_results.assert_called_once() + + # @patch("src.BenchmarkManager.Path.mkdir") + # @patch("builtins.open", new_callable=mock_open) + # @patch("src.BenchmarkManager.logging.getLogger") + # def test_run_benchmark(self, mock_get_logger, mock_open_file, mock_mkdir): + # # Set up a mocked logger + # mock_logger = MagicMock() + # mock_get_logger.return_value = mock_logger + + # # Mock the BenchmarkManager instance and dependencies + # benchmark_manager = BenchmarkManager() + # benchmark_manager.application = MagicMock() + # benchmark_manager.application.metrics = MagicMock() + # benchmark_manager.application.metrics.set_module_config = MagicMock() + # benchmark_manager.application.metrics.set_preprocessing_time = MagicMock() + # benchmark_manager.application.metrics.add_metric = MagicMock() + # benchmark_manager.application.metrics.validate = MagicMock() + # benchmark_manager.application.save = MagicMock() + # benchmark_manager.benchmark_record_template = MagicMock() + # benchmark_manager.store_dir = "/mock/store" + + # # Set up backlog and repetitions + # backlog = [{"config": {"name": "test"}, "submodule": None}] + # repetitions = 1 + + # # Run the benchmark + # benchmark_manager.run_benchmark(backlog, repetitions) + + # # Assertions + # mock_mkdir.assert_called() + # mock_open_file.assert_called_with("/mock/store/benchmark_0/application_config.json", 'w') + # mock_logger.info.assert_called() # Ensure logging calls happen + # benchmark_manager.application.save.assert_called() # Ensure save is called diff --git a/tests/test_ConfigManager.py b/tests/test_ConfigManager.py new file mode 100644 index 00000000..a5adafb9 --- /dev/null +++ b/tests/test_ConfigManager.py @@ -0,0 +1,231 @@ +import unittest +from unittest.mock import patch, MagicMock + +from modules.Core import Core +from src.ConfigManager import ConfigManager + + +class TestConfigManager(unittest.TestCase): + + def setUp(self): + self.config_manager = ConfigManager() + + @patch("src.ConfigManager.inquirer.prompt") + @patch("src.ConfigManager.checkbox") + def test_query_module(self, mock_checkbox, mock_prompt): + # Mock responses for checkbox and prompt + mock_checkbox.return_value = {"param1": [1, 2]} # Simulates a user selecting 1 and 2 + mock_prompt.return_value = {"param2": "a"} # Simulates a user selecting 'a' for param2 + + param_opts = { + "param1": {"values": [1, 2, 3], "description": "Test parameter 1"}, + "param2": {"values": ["a", "b"], "description": "Test parameter 2", "exclusive": True}, + } + + config = ConfigManager._query_for_config(param_opts) + + # Assert the results + self.assertEqual(config["param1"], [1, 2]) + + def test_set_config(self): + config = { + "application": { + "name": "TestApp", + "config": {"param1": 1}, + "submodules": [] + }, + "repetitions": 2 + } + self.config_manager.set_config(config) + + self.assertEqual(self.config_manager.config["application"]["name"], "TestApp") + self.assertEqual(self.config_manager.config["repetitions"], 2) + + def test_is_legacy_config(self): + legacy_config = {"mapping": {"TestMapping": {}}} + modern_config = {"application": {"name": "TestApp"}, "repetitions": 2} + + self.assertTrue(ConfigManager.is_legacy_config(legacy_config)) + self.assertFalse(ConfigManager.is_legacy_config(modern_config)) + + def test_translate_legacy_config_missing_device(self): + # Mock a legacy config + config = { + "application": {"name": "TestApp", "config": {}}, + "repetitions": 1, + "mapping": { + "direct": {"solver": [{"name": "DirectSolver", "config": {}, "device": []}]}, + "solver1": { + "config": {"param1": "value1"}, + "solver": [{"name": "Solver1", "config": {"param2": "value2"}, "device": []}], + }, + }, + } + + # Call the translate_legacy_config method + translated_config = ConfigManager.translate_legacy_config(config) + + # Assertions to verify the output + self.assertIn("application", translated_config) + self.assertIn("repetitions", translated_config) + self.assertEqual(translated_config["repetitions"], 1) + self.assertIn("submodules", translated_config["application"]) + self.assertEqual(len(translated_config["application"]["submodules"]), 2) + + # Verify the structure of the submodules + direct_module = translated_config["application"]["submodules"][0] + self.assertEqual(len(direct_module["submodules"]), 0) + + solver1_module = translated_config["application"]["submodules"][1] + self.assertEqual(solver1_module["name"], "solver1") + self.assertEqual(solver1_module["config"]["param1"], "value1") + self.assertEqual(len(solver1_module["submodules"]), 1) + self.assertEqual(solver1_module["submodules"][0]["name"], "Solver1") + self.assertEqual(solver1_module["submodules"][0]["config"]["param2"], "value2") + + def test_translate_legacy_config_helper(self): + legacy_solver = { + "solver": [ + {"name": "SolverA", "config": {}, "device": [{"name": "DeviceA", "config": {}}]} + ] + } + result = ConfigManager.translate_legacy_config_helper(legacy_solver, "solver") + + # Assertions + self.assertEqual(len(result), 1) + self.assertEqual(result[0]["name"], "SolverA") + self.assertEqual(len(result[0]["submodules"]), 1) + + @patch("src.ConfigManager._get_instance_with_sub_options") + def test_load_config(self, mock_get_instance): + mock_app_instance = MagicMock() + mock_get_instance.return_value = mock_app_instance + + config = { + "application": { + "name": "TestApp", + "config": {"param1": 1}, + "submodules": [] + }, + "repetitions": 2 + } + self.config_manager.set_config(config) + + # Call load_config + self.config_manager.load_config([{"name": "TestApp"}]) + + # Assertions + self.assertEqual(self.config_manager.application, mock_app_instance) + mock_get_instance.assert_called_once_with([{"name": "TestApp"}], "TestApp") + + def test_initialize_module_classes(self): + parent_module = MagicMock(spec=Core) + parent_module.get_submodule = MagicMock(side_effect=lambda name: MagicMock(name=name)) + + config = { + "name": "TestModule", + "config": {"param1": "value1"}, + "submodules": [ + {"name": "SubModule1", "config": {}, "submodules": []}, + {"name": "SubModule2", "config": {}, "submodules": []}, + ], + } + + result = ConfigManager.initialize_module_classes(parent_module, config) + self.assertEqual(result["name"], "TestModule") + self.assertEqual(len(result["submodules"]), 2) + self.assertIn("instance", result) + parent_module.get_submodule.assert_called_with("TestModule") + + def test_get_config(self): + mock_config = {"application": {"name": "TestApp"}, "repetitions": 3} + self.config_manager.config = mock_config + self.assertEqual(self.config_manager.get_config(), mock_config) + + def test_get_app(self): + mock_application = MagicMock() + mock_config = {"application": {"instance": mock_application}} + self.config_manager.config = mock_config + self.assertEqual(self.config_manager.get_app(), mock_application) + + def test_get_reps(self): + mock_config = {"repetitions": 5} + self.config_manager.config = mock_config + self.assertEqual(self.config_manager.get_reps(), 5) + + def test_start_create_benchmark_backlog(self): + mock_application = { + "name": "TestApp", + "config": {"param1": [1, 2]}, + "submodules": [ + { + "name": "SubModule1", + "config": {"sub_param": [3, 4]}, + "submodules": [], + "instance": MagicMock(), + } + ], + "instance": MagicMock(), + } + self.config_manager.config = {"application": mock_application} + backlog = self.config_manager.start_create_benchmark_backlog() + self.assertEqual(len(backlog), 4) + self.assertEqual(backlog[0]["name"], "TestApp") + + def test_create_benchmark_backlog(self): + module = { + "name": "TestModule", + "config": {"param1": [1, 2]}, + "submodules": [ + { + "name": "SubModule1", + "config": {"sub_param": [3, 4]}, + "submodules": [], + "instance": MagicMock(), + } + ], + "instance": MagicMock(), + } + backlog = ConfigManager.create_benchmark_backlog(module) + self.assertEqual(len(backlog), 4) + self.assertEqual(backlog[0]["config"]["param1"], 1) + self.assertEqual(backlog[1]["config"]["param1"], 1) + + def test_save(self): + mock_config = {"application": {"name": "TestApp"}, "repetitions": 3} + self.config_manager.config = mock_config + with patch("builtins.open", unittest.mock.mock_open()) as mocked_open: + self.config_manager.save("/mock/store/dir") + mocked_open.assert_called_once_with("/mock/store/dir/config.yml", "w") + + def test_print(self): + mock_config = {"application": {"name": "TestApp"}, "repetitions": 3} + self.config_manager.config = mock_config + with patch("yaml.dump") as mock_yaml_dump: + self.config_manager.print() + mock_yaml_dump.assert_called_once_with(mock_config) + + def test_create_tree_figure(self): + mock_config = { + "name": "TestApp", + "submodules": [ + {"name": "SubModule1", "submodules": []}, + {"name": "SubModule2", "submodules": []}, + ], + } + self.config_manager.config = {"application": mock_config} + with patch("matplotlib.pyplot.savefig") as mock_savefig: + self.config_manager.create_tree_figure("/mock/store/dir") + mock_savefig.assert_called_once_with("/mock/store/dir/BenchmarkGraph.png", format="PNG") + + @patch("src.ConfigManager.inquirer.prompt") + @patch("src.ConfigManager.checkbox") + def test_query_for_config(self, mock_checkbox, mock_prompt): + mock_checkbox.return_value = {"param1": [1, 2, "Custom Input"]} + mock_prompt.side_effect = [{"custom_input": "custom_value"}] + param_opts = { + "param1": {"values": [1, 2, 3], "description": "Test parameter 1", "custom_input": True} + } + config = ConfigManager._query_for_config(param_opts) + self.assertIn("param1", config) + self.assertEqual(config["param1"], [1, 2, "custom_value"]) diff --git a/tests/testMain.py b/tests/test_Main.py similarity index 99% rename from tests/testMain.py rename to tests/test_Main.py index ef60db4f..0ab2e6fb 100644 --- a/tests/testMain.py +++ b/tests/test_Main.py @@ -15,6 +15,7 @@ import glob import argparse import unittest + from main import handle_benchmark_run, create_benchmark_parser