Skip to content

Commit

Permalink
QML Architecture Updates (#145)
Browse files Browse the repository at this point in the history
* Updated structural changes

* Modified docstrings

---------

Co-authored-by: Greshma Shaji <[email protected]>
  • Loading branch information
Marvmann and GreshmaShaji authored Nov 7, 2024
1 parent 62a87b5 commit 21fa376
Show file tree
Hide file tree
Showing 26 changed files with 3,822 additions and 3,720 deletions.
7,140 changes: 3,570 additions & 3,570 deletions .settings/module_db.json

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions src/modules/applications/qml/Circuit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2021 The QUARK Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from abc import ABC, abstractmethod
from modules.Core import Core


class Circuit(Core, ABC):
"""
This module is abstract base class for the library-agnostic gate sequence, that define a quantum circuit.
"""

@abstractmethod
def generate_gate_sequence(self, input_data: dict, config: any) -> dict:
"""
Generates the library agnostic gate sequence, a well-defined definition of the quantum circuit.
:param input_data: Input data required to generate the gate sequence
:param config: Configuration for the gate sequence
:return: Generated gate sequence
"""
pass
69 changes: 69 additions & 0 deletions src/modules/applications/qml/DataHandler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Copyright 2021 The QUARK Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from abc import ABC, abstractmethod

import pandas as pd
from tensorboard.backend.event_processing.event_accumulator import EventAccumulator


class DataHandler(ABC):
"""
Abstract base class for DataHandler. This class defines the
necessary methods that both supervised and unsupervised QML applciations
must implement.
"""

@abstractmethod
def data_load(self, gen_mod: dict, config: dict) -> tuple[any, float]:
"""
Helps to ensure that the model can effectively learn the underlying
patterns and structure of the data, and produce high-quality outputs.
:param gen_mod: Dictionary with collected information of the previous modules
:param config: Config specifying the parameters of the data handler
:return: Mapped problem and the time it took to create the mapping
"""
pass

@abstractmethod
def evaluate(self, solution: any) -> tuple[any, float]:
"""
Computes the best loss values.
:param solution: Solution data
:return: Evaluation data and the time it took to create it
"""
pass

@staticmethod
def tb_to_pd(logdir: str, rep: str) -> None:
"""
Converts TensorBoard event files in the specified log directory
into a pandas DataFrame and saves it as a pickle file.
:param logdir: Path to the log directory containing TensorBoard event files
:param rep: Repetition counter
"""
event_acc = EventAccumulator(logdir)
event_acc.Reload()
tags = event_acc.Tags()
data = []
tag_data = {}
for tag in tags['scalars']:
data = event_acc.Scalars(tag)
tag_values = [d.value for d in data]
tag_data[tag] = tag_values
data = pd.DataFrame(tag_data, index=[d.step for d in data])
data.to_pickle(f"{logdir}/data_{rep}.pkl")
59 changes: 59 additions & 0 deletions src/modules/applications/qml/Model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright 2021 The QUARK Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and

from abc import ABC, abstractmethod


class Model(ABC):
"""
Abstract base class for any quantum model. This class defines the necessary methods
that models like 'LibraryGenerative' must implement.
"""

@abstractmethod
def sequence_to_circuit(self, input_data: dict) -> dict:
"""
Abstract method to convert a sequence into a quantum circuit.
:param input_data: Input data representing the gate sequence
:return: A dictionary representing the quantum circuit
"""
pass

@staticmethod
@abstractmethod
def get_execute_circuit(circuit: any, backend: any, config: str, config_dict: dict) -> tuple[any, any]:
"""
This method combines the circuit implementation and the selected backend and returns a function that will be
called during training.
:param circuit: Implementation of the quantum circuit
:param backend: Configured qiskit backend
:param config: Name of a backend
:param config_dict: Dictionary including the number of shots
:return: Tuple that contains a method that executes the quantum circuit for a given set of parameters and the
transpiled circuit
"""
pass

@staticmethod
@abstractmethod
def select_backend(config: str, n_qubits: int) -> any:
"""
This method configures the backend.
:param config: Name of a backend
:param n_qubits: Number of qubits
:return: Configured backend
"""
pass
33 changes: 33 additions & 0 deletions src/modules/applications/qml/Training.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2021 The QUARK Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from abc import ABC, abstractmethod


class Training(ABC):
"""
Abstract base class for training QML models.
"""

@abstractmethod
def start_training(self, input_data: dict, config: any, **kwargs: dict) -> dict:
"""
This function starts the training of QML model or deploys a pretrained model.
:param input_data: A representation of the quantum machine learning model that will be trained
:param config: Config specifying the parameters of the training (dict-like Config type defined in children)
:param kwargs: Optional additional settings
:return: Solution, the time it took to compute it and some optional additional information
"""
pass
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@

from typing import Union, TypedDict

from modules.circuits.Circuit import Circuit
from modules.applications.qml.generative_modeling.circuits.CircuitGenerative import CircuitGenerative
from modules.applications.qml.generative_modeling.mappings.LibraryQiskit import LibraryQiskit
from modules.applications.qml.generative_modeling.mappings.LibraryPennylane import LibraryPennylane
from modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend import PresetQiskitNoisyBackend
from modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend import CustomQiskitNoisyBackend


class CircuitCardinality(Circuit):
class CircuitCardinality(CircuitGenerative):
"""
This class generates a library-agnostic gate sequence, i.e. a list containing information
about the gates and the wires they act on.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
from itertools import combinations
from scipy.special import binom

from modules.circuits.Circuit import Circuit
from modules.applications.qml.generative_modeling.circuits.CircuitGenerative import CircuitGenerative
from modules.applications.qml.generative_modeling.mappings.LibraryQiskit import LibraryQiskit
from modules.applications.qml.generative_modeling.mappings.LibraryPennylane import LibraryPennylane
from modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend import PresetQiskitNoisyBackend
from modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend import CustomQiskitNoisyBackend


class CircuitCopula(Circuit):
class CircuitCopula(CircuitGenerative):
"""
This class generates a library-agnostic gate sequence, i.e. a list containing information
about the gates and the wires they act on. The marginal distributions generated by the copula
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from abc import ABC, abstractmethod
from abc import ABC
from modules.Core import Core
from utils import start_time_measurement, end_time_measurement

from modules.applications.qml.Circuit import Circuit

class Circuit(Core, ABC):

class CircuitGenerative(Circuit, Core, ABC):
"""
This module is abstract base class for the library-agnostic gate sequence, that define a quantum circuit.
"""
Expand All @@ -31,17 +33,6 @@ def __init__(self, name: str):
super().__init__()
self.architecture_name = name

@abstractmethod
def generate_gate_sequence(self, input_data: dict, config: any) -> dict:
"""
Generates the library agnostic gate sequence, a well-defined definition of the quantum circuit.
:param input_data: Input data required to generate the gate sequence
:param config: Configuration for the gate sequence
:return: Generated gate sequence
"""
pass

def preprocess(self, input_data: dict, config: dict, **kwargs) -> tuple[dict, float]:
"""
Library-agnostic implementation of the gate sequence, that will be mapped to backend such as Qiskit in the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@

from typing import Union, TypedDict

from modules.circuits.Circuit import Circuit
from modules.applications.qml.generative_modeling.circuits.CircuitGenerative import CircuitGenerative
from modules.applications.qml.generative_modeling.mappings.LibraryQiskit import LibraryQiskit
from modules.applications.qml.generative_modeling.mappings.LibraryPennylane import LibraryPennylane
from modules.applications.qml.generative_modeling.mappings.PresetQiskitNoisyBackend import PresetQiskitNoisyBackend
from modules.applications.qml.generative_modeling.mappings.CustomQiskitNoisyBackend import CustomQiskitNoisyBackend


class CircuitStandard(Circuit):
class CircuitStandard(CircuitGenerative):
"""
This class generates a library-agnostic gate sequence, i.e. a list containing information
about the gates and the wires they act on.
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
from utils import start_time_measurement, end_time_measurement
from modules.applications.qml.generative_modeling.transformations.MinMax import MinMax
from modules.applications.qml.generative_modeling.transformations.PIT import PIT
from modules.applications.qml.generative_modeling.data.data_handler.DataHandler import DataHandler
from modules.applications.qml.generative_modeling.data.data_handler.DataHandlerGenerative import DataHandlerGenerative


class ContinuousData(DataHandler):
class ContinuousData(DataHandlerGenerative):
"""
A data handler for continuous datasets. This class loads a dataset from a specified path and provides
methods for data transformation and evaluation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,17 @@

import pickle
import os
from abc import ABC, abstractmethod
from abc import ABC
from qiskit import qpy

import numpy as np
import pandas as pd
from tensorboard.backend.event_processing.event_accumulator import EventAccumulator

from modules.Core import Core
from modules.applications.qml.DataHandler import DataHandler
from utils import start_time_measurement, end_time_measurement


class DataHandler(Core, ABC):
class DataHandlerGenerative(Core, DataHandler, ABC):
"""
The task of the DataHandler module is to translate the application’s data
and problem specification into preprocessed format.
Expand Down Expand Up @@ -103,7 +102,7 @@ def postprocess(self, input_data: dict, config: dict, **kwargs) -> tuple[dict, f

# Save metrics per iteration
if "inference" not in input_data.keys():
DataHandler.tb_to_pd(logdir=store_dir_iter, rep=str(kwargs['rep_count']))
self.tb_to_pd(logdir=store_dir_iter, rep=str(kwargs['rep_count']))
self.metrics.add_metric_batch(
{"metrics_pandas": os.path.relpath(f"{store_dir_iter}/data.pkl", current_directory)}
)
Expand Down Expand Up @@ -155,18 +154,6 @@ def postprocess(self, input_data: dict, config: dict, **kwargs) -> tuple[dict, f

return input_data, end_time_measurement(start)

@abstractmethod
def data_load(self, gen_mod: dict, config: dict) -> tuple[any, float]:
"""
Helps to ensure that the model can effectively learn the underlying
patterns and structure of the data, and produce high-quality outputs.
:param gen_mod: Dictionary with collected information of the previous modules
:param config: Config specifying the parameters of the data handler
:return: Mapped problem and the time it took to create the mapping
"""
pass

def generalization(self) -> tuple[dict, float]:
"""
Computes generalization metrics.
Expand All @@ -177,34 +164,3 @@ def generalization(self) -> tuple[dict, float]:
metrics = {} # Replace with actual metric calculations
time_taken = 0.0 # Replace with actual time calculation
return metrics, time_taken

@abstractmethod
def evaluate(self, solution: any) -> tuple[any, float]:
"""
Computes the best loss values.
:param solution: Solution data
:return: Evaluation data and the time it took to create it
"""
return None, 0.0

@staticmethod
def tb_to_pd(logdir: str, rep: str) -> None:
"""
Converts TensorBoard event files in the specified log directory
into a pandas DataFrame and saves it as a pickle file.
:param logdir: Path to the log directory containing TensorBoard event files
:param rep: Repetition counter
"""
event_acc = EventAccumulator(logdir)
event_acc.Reload()
tags = event_acc.Tags()
data = []
tag_data = {}
for tag in tags['scalars']:
data = event_acc.Scalars(tag)
tag_values = [d.value for d in data]
tag_data[tag] = tag_values
data = pd.DataFrame(tag_data, index=[d.step for d in data])
data.to_pickle(f"{logdir}/data_{rep}.pkl")
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@

import numpy as np

from modules.circuits.CircuitCardinality import CircuitCardinality
from modules.applications.qml.generative_modeling.data.data_handler.DataHandler import DataHandler
from modules.applications.qml.generative_modeling.data.data_handler.MetricsGeneralization import MetricsGeneralization
from modules.applications.qml.generative_modeling.circuits.CircuitCardinality import CircuitCardinality
from modules.applications.qml.generative_modeling.data.data_handler.DataHandlerGenerative import DataHandlerGenerative
from modules.applications.qml.generative_modeling.metrics.MetricsGeneralization import MetricsGeneralization
from utils import start_time_measurement, end_time_measurement


class DiscreteData(DataHandler):
class DiscreteData(DataHandlerGenerative):
"""
A data handler for discrete datasets with cardinality constraints.
This class creates a dataset with a cardinality constraint and provides
Expand Down
Loading

0 comments on commit 21fa376

Please sign in to comment.