-
Notifications
You must be signed in to change notification settings - Fork 5
Optimizer
Author: https://github.com/Supercabb
License: MIT
LILY QML 2024 - Leon Kaiser
The Optimizer class is designed to handle the optimization process within the LILY-QML project. It manages the initialization of qubits, loading of data, parsing and execution of jobs, and interaction with optimizer algorithms. The class ensures that data structures are correctly formatted and that the optimization process runs smoothly.
- Purpose: Coordinate the optimization of quantum circuits by interfacing with optimizer algorithms and managing qubit states.
-
Key Responsibilities:
- Load and validate optimizer modules.
- Initialize qubit objects.
- Parse and evaluate job strings.
- Execute optimization steps.
- Update training matrices based on optimization results.
-
Qubit_Object(dict): A dictionary mapping qubit indices toQubitinstances.self.Qubit_Object = {0: Qubit(0), 1: Qubit(1), ...}
-
current_job(str): The job string currently being processed.self.current_job = "(1.0, 2.0, 3.0) Qubit_0 (1:200; 0:50) (S:1)"
-
optimizer(str): The name of the optimizer class to be used.self.optimizer = "AdaGradOptimizer"
-
optimizer_class(class): The optimizer class imported dynamically based onoptimizer.self.optimizer_class = <class 'AdaGradOptimizer'>
-
config_path(str): Path to the configuration directory.self.config_path = "var"
-
dict_params_current_job(dict): A dictionary containing parsed parameters from thecurrent_jobstring.self.dict_params_current_job = { "matrix_row_str": "1.0, 2.0, 3.0", "num_qubit": "0", "dist_0_0": "1", "vdist_0_1": "200", "dist_1_0": "0", "dist_1_1": "50", "state": "1", "matrix_elements": [1.0, 2.0, 3.0] }
-
target_state(str): The desired target state for the qubits.self.target_state = "101"
-
train_json_file_path(str): File path totrain.json.self.train_json_file_path = "var/train.json"
-
train_json_data(dict): Data loaded fromtrain.json.self.train_json_data = {...}
-
logger(Logger): Logger instance for logging messages.self.logger = logging.getLogger()
-
data_json(dict): Data loaded fromdata.json.self.data_json = {...}
Description: Initializes the Optimizer instance, setting up default values and paths.
Parameters:
-
config_path(str): Path to the configuration directory (default:'var').
Data Structures:
- Initializes empty or default values for attributes.
Method Calls:
- None.
Description: Checks if the specified optimizer exists and initializes qubits based on data.json.
Return:
-
Noneif successful. -
dictwith error code and message if an error occurs.
Data Structures:
- Updates
self.optimizer_classwith the imported optimizer class. - Loads
self.data_jsonfromdata.json.
Method Calls:
initialize_qubits(num_qubits)
Process:
-
Optimizer Module Loading:
- Constructs the module name based on
self.optimizer. - Attempts to import the optimizer module and class.
- If unsuccessful, returns an error:
{"Error Code": 1111, "Message": "Optimizer not found."}
- Constructs the module name based on
-
Data Loading:
- Attempts to load
data.json. - If unsuccessful, returns an error:
{"Error Code": 1112, "Message": "Data file not found."}
- Attempts to load
-
Qubit Initialization:
- Calls
initialize_qubits(num_qubits)with the number of qubits fromdata.json.
- Calls
Description: Initializes qubit objects and stores them in self.Qubit_Object.
Parameters:
-
num_qubits(int): The number of qubits to initialize.
Data Structures:
- Updates
self.Qubit_Objectwith qubit instances.
Method Calls:
- Instantiates
Qubitobjects.
Process:
- Iterates over the range of
num_qubitsand creates aQubitinstance for each index.
Description: Parses the current_job string to extract relevant fields.
Parameters:
-
job(str): The job string to parse.
Return:
-
fields(dict): A dictionary containing extracted fields if parsing is successful. -
Noneif parsing fails.
Data Structures:
- Uses regular expressions to extract fields.
Method Calls:
- Uses
re.matchfor pattern matching.
Process:
- Defines a regex pattern to match the job string.
- Extracts fields such as
matrix_row_str,num_qubit, distributions, andstate.
Description: Converts the matrix string from the job into a list of floating-point numbers.
Parameters:
-
matrix_str(str): The string containing matrix elements.
Return:
-
matrix_elements(listoffloat): List of matrix elements. -
Noneif conversion fails.
Data Structures:
- Parses the string and converts elements to floats.
Method Calls:
- Uses
re.findallto extract numbers.
Process:
- Uses a regex pattern to find all numeric strings.
- Converts each string to a float and appends to
matrix_elements.
Description: Validates the structure of the current_job and extracts necessary fields.
Return:
-
Noneif successful. -
dictwith error code and message if validation fails.
Data Structures:
- Updates
self.dict_params_current_jobwith parsed data.
Method Calls:
extract_fields_from_job(self.current_job)extract_matrix_from_string(matrix_row_str)
Process:
- Calls
extract_fields_from_jobto parse the job string. - If parsing fails, logs an error and returns an error code.
- Extracts matrix elements using
extract_matrix_from_string. - If extraction fails, logs an error and returns an error code.
- Updates
self.dict_params_current_jobwithmatrix_elements.
Description: Evaluates the current job by parsing it and loading the state into the corresponding qubit.
Parameters:
-
current_job(str): The job string to evaluate.
Data Structures:
- Updates
self.current_job. - Updates qubit state in
self.Qubit_Object.
Method Calls:
check_data_structure()Qubit.load_state(state)
Process:
- Sets
self.current_jobtocurrent_job. - Calls
check_data_structure()to validate and parse the job. - If validation fails, the process stops.
- Loads the state into the corresponding qubit:
num_qubit = int(self.dict_params_current_job["num_qubit"]) state = self.dict_params_current_job["state"] self.Qubit_Object[num_qubit].load_state(state)
Description: Executes the optimization process for the current job and returns a new job string.
Parameters:
-
current_job(str): The job string to execute.
Return:
-
new_job(str): The updated job string after optimization.
Data Structures:
- Interacts with optimizer instance.
- Updates qubit loss function.
Method Calls:
evaluate(current_job)- Instantiates optimizer class.
optimizer.evaluate()optimizer.calculate_loss()optimizer.compute_gradient()optimizer.optimize()Qubit.load_function(loss)
Process:
- Calls
evaluate(current_job)to parse and load the job. - Instantiates the optimizer:
optimizer = self.optimizer_class(self.data_json, self.dict_params_current_job["matrix_elements"], self.dict_params_current_job["state"])
- Runs optimization steps:
optimizer.evaluate()loss = optimizer.calculate_loss()optimizer.compute_gradient()tuning_parameters, optimization_steps = optimizer.optimize()
- Updates qubit with loss function:
num_qubit = int(self.dict_params_current_job["num_qubit"]) self.Qubit_Object[num_qubit].load_function(loss)
- Constructs the new job string with updated tuning parameters and logs it.
Description: Initializes the optimizer process by validating the optimizer and target state.
Parameters:
-
optimizer(str): The name of the optimizer to use. -
target_state(str): The desired target state for the qubits.
Return:
-
Noneif successful. -
dictwith error code and message if an error occurs.
Data Structures:
- Updates
self.optimizerandself.target_state.
Method Calls:
- Validates the existence of the optimizer file.
check_prerequisites()
Process:
- Sets
self.optimizerandself.target_state. - Constructs the optimizer file path and checks if it exists.
- If not found, returns an error:
{"Error Code": 1072, "Message": "Optimizer not found."} - Calls
check_prerequisites()to load the optimizer and initialize qubits. - Validates the length of
target_stateagainst the number of qubits. - Checks for the existence of
train.json. - Loads
train.jsondata intoself.train_json_data. - Logs success messages.
Description: Performs the optimization process using the given measurements and training matrix.
Parameters:
-
measurement(dict): Measurement data with keys as bitstrings and values as counts.measurement = {"000": 512, "101": 488}
-
training_matrix(listoflist): The current training matrix.training_matrix = [ [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0], [9.0, 10.0, 11.0, 12.0] ]
Return:
-
new_training_matrix(listoflist): The updated training matrix after optimization. -
Noneif an error occurs.
Data Structures:
- Updates qubit training matrices and distributions.
- Constructs
new_training_matrix.
Method Calls:
encode_measurements(measurement)Qubit.load_training_matrix(matrix_str)Qubit.load_actual_distribution(distribution)execute(current_job)
Process:
- Logs the start of the optimization process.
- Calls
encode_measurements(measurement)to get qubit-wise measurements. - Validates the length of
training_matrix. - For each qubit:
- Converts training matrix row to string.
- Loads the training matrix and actual distribution into the qubit.
- Initializes
new_training_matrixas an empty list. - For each qubit:
- Constructs the
current_jobstring. - Calls
execute(current_job)to perform optimization. - Extracts updated matrix elements and appends to
new_training_matrix.
- Constructs the
- Logs success messages and returns
new_training_matrix.
Description: Converts measurement data into qubit-wise distributions.
Parameters:
-
measurement(dict): Measurement data with keys as bitstrings and values as counts.
Return:
-
qubits_measurement(listofstr): List of qubit measurement strings.qubits_measurement = ["(1:488; 0:512)", "(1:0; 0:1000)", "(1:488; 0:512)"]
-
Noneif an error occurs.
Data Structures:
- Uses NumPy arrays to count measurements per qubit.
Method Calls:
- None.
Process:
- Validates the length of bitstrings in
measurement. - Initializes a NumPy array
qubits_measurement_countwith zeros. - Iterates over the measurements:
- For each bitstring and count:
- Updates
qubits_measurement_countper qubit and bit value.
- Updates
- For each bitstring and count:
- Constructs
qubits_measurementas a list of strings representing qubit distributions.
-
start():- Calls
check_prerequisites().- Calls
initialize_qubits(num_qubits).
- Calls
- Validates optimizer file and
train.json.
- Calls
-
optimize():- Calls
encode_measurements(measurement). - Iterates over qubits:
- Calls
Qubit.load_training_matrix(matrix_str). - Calls
Qubit.load_actual_distribution(distribution). - Constructs
current_joband callsexecute(current_job).- Calls
evaluate(current_job).- Calls
check_data_structure().- Calls
extract_fields_from_job(self.current_job). - Calls
extract_matrix_from_string(matrix_row_str).
- Calls
- Calls
Qubit.load_state(state).
- Calls
- Instantiates optimizer and runs optimization steps.
- Calls
Qubit.load_function(loss).
- Calls
- Calls
- Calls
-
Error Dictionaries:
{"Error Code": 1111, "Message": "Optimizer not found."} -
new_training_matrix(listoflist):- After optimization, a list of lists containing updated tuning parameters.
new_training_matrix = [ [updated_values_for_qubit_0], [updated_values_for_qubit_1], ... ]
-
qubits_measurement(listofstr):- Encoded measurement data per qubit.
qubits_measurement = ["(1:488; 0:512)", "(1:0; 0:1000)", "(1:488; 0:512)"]
-
self.dict_params_current_job(dict):- Contains parsed fields from the job string, including matrix elements.
self.dict_params_current_job = { "matrix_row_str": "1.0, 2.0, 3.0", "num_qubit": "0", "dist_0_0": "1", "vdist_0_1": "200", "dist_1_0": "0", "dist_1_1": "50", "state": "1", "matrix_elements": [1.0, 2.0, 3.0] }
- Error Handling: The class methods return error dictionaries when issues are encountered, which include an error code and message.
- Logging: The class uses a logger to log messages at various points, which helps in debugging and tracking the process flow.
- Regular Expressions: Used extensively in parsing job strings and extracting data.
optimizer = Optimizer()
optimizer.start("AdaGradOptimizer", "101")
measurement = {"000": 512, "101": 488}
training_matrix = [
[1.0, 2.0, 3.0, 4.0],
[5.0, 6.0, 7.0, 8.0],
[9.0, 10.0, 11.0, 12.0]
]
new_training_matrix = optimizer.optimize(measurement, training_matrix)In this example:
- The optimizer is initialized and started with the
AdaGradOptimizerand a target state of"101". - Measurements are provided as a dictionary mapping bitstrings to counts.
- A training matrix is provided.
- The
optimize()method returns an updated training matrix after performing optimization.