From 821c4c55ad896fa7809f7fb4c592026747b74147 Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Wed, 24 May 2023 21:12:28 +0200 Subject: [PATCH 01/16] Corrected int_to_bitlist --- plugins/quantum_k_nearest_neighbours/backend/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/quantum_k_nearest_neighbours/backend/utils.py b/plugins/quantum_k_nearest_neighbours/backend/utils.py index 95c51fd39..79e115924 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/utils.py +++ b/plugins/quantum_k_nearest_neighbours/backend/utils.py @@ -27,7 +27,7 @@ def bitlist_to_int(bitlist: List[int]) -> int: def int_to_bitlist(num, length: int): binary = bin(num)[2:] - result = [int(el) for el in reversed(binary)] + result = [int(el) for el in binary] if len(result) > length: raise ValueError( f"Binary representation of {num} needs at least {len(result)} bits, but only got {length}." From e22137ed2602bd65fff5eec48e0e8c9182c3d389 Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Wed, 24 May 2023 21:15:50 +0200 Subject: [PATCH 02/16] QAM using self.X now after assigning X to self.X --- .../data_loading_circuits/quantum_associative_memory.py | 4 ++-- .../data_loading_circuits/quantum_associative_memory.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/quantum_k_nearest_neighbours/backend/data_loading_circuits/quantum_associative_memory.py b/plugins/quantum_k_nearest_neighbours/backend/data_loading_circuits/quantum_associative_memory.py index 4116bfe78..1a0999ab3 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/data_loading_circuits/quantum_associative_memory.py +++ b/plugins/quantum_k_nearest_neighbours/backend/data_loading_circuits/quantum_associative_memory.py @@ -47,7 +47,7 @@ def __init__( raise ValueError( "A QAM (Quantum Associative Memory) can only load binary data" ) - self.xor_X = self.create_xor_X(X) + self.xor_X = self.create_xor_X(self.X) if additional_bits is not None: if not is_binary(additional_bits): @@ -90,7 +90,7 @@ def __init__( self.ancilla_wires = self.ancilla_wires[2:] if amplitudes is None: - self.amplitudes = [1 / np.sqrt(X.shape[0], dtype=np.float64)] * X.shape[0] + self.amplitudes = [1 / np.sqrt(self.X.shape[0], dtype=np.float64)] * self.X.shape[0] else: self.amplitudes = amplitudes diff --git a/plugins/quantum_parzen_window/backend/data_loading_circuits/quantum_associative_memory.py b/plugins/quantum_parzen_window/backend/data_loading_circuits/quantum_associative_memory.py index 4116bfe78..1a0999ab3 100644 --- a/plugins/quantum_parzen_window/backend/data_loading_circuits/quantum_associative_memory.py +++ b/plugins/quantum_parzen_window/backend/data_loading_circuits/quantum_associative_memory.py @@ -47,7 +47,7 @@ def __init__( raise ValueError( "A QAM (Quantum Associative Memory) can only load binary data" ) - self.xor_X = self.create_xor_X(X) + self.xor_X = self.create_xor_X(self.X) if additional_bits is not None: if not is_binary(additional_bits): @@ -90,7 +90,7 @@ def __init__( self.ancilla_wires = self.ancilla_wires[2:] if amplitudes is None: - self.amplitudes = [1 / np.sqrt(X.shape[0], dtype=np.float64)] * X.shape[0] + self.amplitudes = [1 / np.sqrt(self.X.shape[0], dtype=np.float64)] * self.X.shape[0] else: self.amplitudes = amplitudes From 02b439c5f0be8a179fd2993c3fecd709f4831690 Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Wed, 24 May 2023 21:16:45 +0200 Subject: [PATCH 03/16] SimpleHammingQkNN can now handle duplicates in training data --- .../backend/qknns/qknn.py | 4 +- .../backend/qknns/simpleQkNN.py | 41 ++++++++++--------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/plugins/quantum_k_nearest_neighbours/backend/qknns/qknn.py b/plugins/quantum_k_nearest_neighbours/backend/qknns/qknn.py index 6c84d3d38..bcff8bd4a 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/qknns/qknn.py +++ b/plugins/quantum_k_nearest_neighbours/backend/qknns/qknn.py @@ -103,10 +103,10 @@ def get_qknn_and_total_wires( SimpleHammingQkNN, max_wires, train_data=train_data ) if use_access_wires: - wires[1] = wires[1] + access_wires + wires[2] = wires[2] + access_wires return SimpleHammingQkNN( - train_data, train_labels, k, wires[0], wires[1], None + train_data, train_labels, k, wires[0], wires[1], wires[2], None ), count_wires(wires) elif self == QkNNEnum.simple_fidelity_qknn: from .simpleQkNN import SimpleFidelityQkNN diff --git a/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py b/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py index f295ae4ec..3fae85e4c 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py +++ b/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py @@ -21,7 +21,7 @@ from .qknn import QkNN from ..data_loading_circuits import QAM from ..data_loading_circuits import TreeLoader -from ..utils import bitlist_to_int, check_binary, ceil_log2, check_for_duplicates +from ..utils import int_to_bitlist, bitlist_to_int, check_binary, ceil_log2 from ..check_wires import check_wires_uniqueness, check_num_wires @@ -52,12 +52,15 @@ def label_point(self, x: np.ndarray) -> int: new_label = np.bincount(self.train_labels).argmax() else: distances = np.array(self.calculate_distances(x)) # Get distances + print(f"distances: {distances}") indices = np.argpartition(distances, self.k)[ : self.k ] # Get k smallest values + print(f"{self.k} indices with smallest value: {indices}") counts = Counter( self.train_labels[indices] ) # Count occurrences of labels in k smallest values + print(f"label counts: {counts}") new_label = max(counts, key=counts.get) # Get most frequent label return new_label @@ -68,6 +71,7 @@ def __init__( train_data: np.ndarray, train_labels: np.ndarray, k: int, + idx_wires: List[int], train_wires: List[int], qam_ancilla_wires: List[int], backend: qml.Device, @@ -79,31 +83,30 @@ def __init__( self.train_data, "All the data needs to be binary, when dealing with the hamming distance", ) - check_for_duplicates( - self.train_data, "The training data may not contain duplicates." - ) self.train_data = np.array(train_data, dtype=int) - self.point_num_to_idx = {} - for i, vec in enumerate(self.train_data): - self.point_num_to_idx[bitlist_to_int(vec)] = i - self.unclean_wires = [] if unclean_wires is None else unclean_wires + self.idx_wires = idx_wires self.train_wires = train_wires self.qam_ancilla_wires = qam_ancilla_wires - wire_types = ["train", "qam_ancilla", "unclean"] - num_wires = [self.train_data.shape[1], max(self.train_data.shape[1], 2)] + wire_types = ["idx", "train", "qam_ancilla", "unclean"] + num_idx_wires = int(np.ceil(np.log2(self.train_data.shape[0]))) + num_wires = [num_idx_wires, self.train_data.shape[1], max(self.train_data.shape[0], 2)] error_msgs = [ + "the round up log2 of the number of points, i.e. ceil(log2(no. points))." "the points' dimensionality.", "the points' dimensionality and greater or equal to 2.", ] + check_wires_uniqueness(self, wire_types) check_num_wires(self, wire_types[:-1], num_wires, error_msgs) self.qam = QAM( - self.train_data, - self.train_wires, + np.array([int_to_bitlist(i, num_idx_wires) for i in range(self.train_data.shape[0])]), # The indices + self.idx_wires, self.qam_ancilla_wires, unclean_wires=self.unclean_wires, + additional_wires=self.train_wires, + additional_bits=self.train_data, ) def get_quantum_circuit(self, x: np.ndarray): @@ -130,10 +133,8 @@ def quantum_circuit(): for train_wire in self.train_wires: # QAM ancilla wires are 0 after QAM -> use one of those wires qml.CRX(rot_angle, wires=(train_wire, self.qam_ancilla_wires[0])) - for x_, train_wire in zip(x, self.train_wires): - if x_ == 0: - qml.PauliX((train_wire,)) - return qml.sample(wires=self.train_wires + [self.qam_ancilla_wires[0]]) + + return qml.sample(wires=self.idx_wires + [self.qam_ancilla_wires[0]]) return quantum_circuit @@ -144,8 +145,8 @@ def calculate_distances(self, x: np.ndarray) -> List[float]: # Count how often a certain point was measured (total_ancilla) # and how often the ancilla qubit was zero (num_zero_ancilla) for sample in samples: - idx = self.point_num_to_idx.get(bitlist_to_int(sample[:-1]), None) - if idx is not None: + idx = bitlist_to_int(sample[:-1]) + if idx < len(self.train_data): total_ancilla[idx] += 1 if sample[-1] == 0: num_zero_ancilla[idx] += 1 @@ -159,8 +160,8 @@ def calculate_distances(self, x: np.ndarray) -> List[float]: return num_zero_ancilla @staticmethod - def get_necessary_wires(train_data: np.ndarray) -> Tuple[int, int]: - return len(train_data[0]), max(len(train_data[0]), 2) + def get_necessary_wires(train_data: np.ndarray) -> Tuple[int, int, int]: + return int(np.ceil(np.log2(train_data.shape[0]))), len(train_data[0]), max(len(train_data[0]), 2) def get_representative_circuit(self, X: np.ndarray) -> str: circuit = qml.QNode(self.get_quantum_circuit(X[0]), self.backend) From f5cb65f30f196df2580ccdb9d1c54c2f22f823cb Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Wed, 24 May 2023 21:23:07 +0200 Subject: [PATCH 04/16] Ensure black format --- .../quantum_associative_memory.py | 4 +++- .../backend/qknns/simpleQkNN.py | 19 ++++++++++++++++--- .../quantum_associative_memory.py | 4 +++- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/plugins/quantum_k_nearest_neighbours/backend/data_loading_circuits/quantum_associative_memory.py b/plugins/quantum_k_nearest_neighbours/backend/data_loading_circuits/quantum_associative_memory.py index 1a0999ab3..f7504f974 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/data_loading_circuits/quantum_associative_memory.py +++ b/plugins/quantum_k_nearest_neighbours/backend/data_loading_circuits/quantum_associative_memory.py @@ -90,7 +90,9 @@ def __init__( self.ancilla_wires = self.ancilla_wires[2:] if amplitudes is None: - self.amplitudes = [1 / np.sqrt(self.X.shape[0], dtype=np.float64)] * self.X.shape[0] + self.amplitudes = [ + 1 / np.sqrt(self.X.shape[0], dtype=np.float64) + ] * self.X.shape[0] else: self.amplitudes = amplitudes diff --git a/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py b/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py index 3fae85e4c..65263a5ad 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py +++ b/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py @@ -91,7 +91,11 @@ def __init__( self.qam_ancilla_wires = qam_ancilla_wires wire_types = ["idx", "train", "qam_ancilla", "unclean"] num_idx_wires = int(np.ceil(np.log2(self.train_data.shape[0]))) - num_wires = [num_idx_wires, self.train_data.shape[1], max(self.train_data.shape[0], 2)] + num_wires = [ + num_idx_wires, + self.train_data.shape[1], + max(self.train_data.shape[0], 2), + ] error_msgs = [ "the round up log2 of the number of points, i.e. ceil(log2(no. points))." "the points' dimensionality.", @@ -101,7 +105,12 @@ def __init__( check_wires_uniqueness(self, wire_types) check_num_wires(self, wire_types[:-1], num_wires, error_msgs) self.qam = QAM( - np.array([int_to_bitlist(i, num_idx_wires) for i in range(self.train_data.shape[0])]), # The indices + np.array( + [ + int_to_bitlist(i, num_idx_wires) + for i in range(self.train_data.shape[0]) + ] + ), # The indices self.idx_wires, self.qam_ancilla_wires, unclean_wires=self.unclean_wires, @@ -161,7 +170,11 @@ def calculate_distances(self, x: np.ndarray) -> List[float]: @staticmethod def get_necessary_wires(train_data: np.ndarray) -> Tuple[int, int, int]: - return int(np.ceil(np.log2(train_data.shape[0]))), len(train_data[0]), max(len(train_data[0]), 2) + return ( + int(np.ceil(np.log2(train_data.shape[0]))), + len(train_data[0]), + max(len(train_data[0]), 2), + ) def get_representative_circuit(self, X: np.ndarray) -> str: circuit = qml.QNode(self.get_quantum_circuit(X[0]), self.backend) diff --git a/plugins/quantum_parzen_window/backend/data_loading_circuits/quantum_associative_memory.py b/plugins/quantum_parzen_window/backend/data_loading_circuits/quantum_associative_memory.py index 1a0999ab3..f7504f974 100644 --- a/plugins/quantum_parzen_window/backend/data_loading_circuits/quantum_associative_memory.py +++ b/plugins/quantum_parzen_window/backend/data_loading_circuits/quantum_associative_memory.py @@ -90,7 +90,9 @@ def __init__( self.ancilla_wires = self.ancilla_wires[2:] if amplitudes is None: - self.amplitudes = [1 / np.sqrt(self.X.shape[0], dtype=np.float64)] * self.X.shape[0] + self.amplitudes = [ + 1 / np.sqrt(self.X.shape[0], dtype=np.float64) + ] * self.X.shape[0] else: self.amplitudes = amplitudes From 0d6b4b6db92302d09a252e7c95169f55933b940a Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Wed, 24 May 2023 21:57:41 +0200 Subject: [PATCH 05/16] Fixed schuld_hamming (previously, it chose the least similar label). schuld_hamming can now handle duplicates. --- .../backend/qknns/qknn.py | 4 +-- .../backend/qknns/schuld_hamming.py | 31 ++++++++++++------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/plugins/quantum_k_nearest_neighbours/backend/qknns/qknn.py b/plugins/quantum_k_nearest_neighbours/backend/qknns/qknn.py index bcff8bd4a..ed835cc18 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/qknns/qknn.py +++ b/plugins/quantum_k_nearest_neighbours/backend/qknns/qknn.py @@ -91,10 +91,10 @@ def get_qknn_and_total_wires( SchuldQkNN, max_wires, train_data=train_data, train_labels=train_labels ) if use_access_wires: - wires[2] = wires[2] + access_wires + wires[3] = wires[3] + access_wires return SchuldQkNN( - train_data, train_labels, wires[0], wires[1], wires[2], None + train_data, train_labels, wires[0], wires[1], wires[2], wires[3], None ), count_wires(wires) elif self == QkNNEnum.simple_hamming_qknn: from .simpleQkNN import SimpleHammingQkNN diff --git a/plugins/quantum_k_nearest_neighbours/backend/qknns/schuld_hamming.py b/plugins/quantum_k_nearest_neighbours/backend/qknns/schuld_hamming.py index cd4fda9fb..04a7c5f29 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/qknns/schuld_hamming.py +++ b/plugins/quantum_k_nearest_neighbours/backend/qknns/schuld_hamming.py @@ -33,6 +33,7 @@ def __init__( self, train_data: np.ndarray, train_labels: np.ndarray, + idx_wires: List[int], train_wires: List[int], label_wires: List[int], qam_ancilla_wires: List[int], @@ -48,21 +49,20 @@ def __init__( "All the data needs to be binary, when dealing with the hamming distance", ) - check_for_duplicates( - self.train_data, "The training data may not contain duplicates." - ) - self.train_data = np.array(train_data, dtype=int) self.label_indices = self.init_labels(train_labels) self.unclean_wires = [] if unclean_wires is None else unclean_wires + self.idx_wires = idx_wires self.train_wires = train_wires self.qam_ancilla_wires = qam_ancilla_wires self.label_wires = label_wires - wire_types = ["train", "label", "qam_ancilla", "unclean"] + wire_types = ["idx", "train", "label", "qam_ancilla", "unclean"] + num_idx_wires = int(np.ceil(np.log2(self.train_data.shape[0]))) num_wires = [ + num_idx_wires, self.train_data.shape[1], self.label_indices.shape[1], max(self.train_data.shape[1], 2), @@ -76,11 +76,16 @@ def __init__( check_num_wires(self, wire_types[:-1], num_wires, error_msgs) self.qam = QAM( - self.train_data, - self.train_wires, + np.array( + [ + int_to_bitlist(i, num_idx_wires) + for i in range(self.train_data.shape[0]) + ] + ), # The indices + self.idx_wires, self.qam_ancilla_wires, - additional_bits=self.label_indices, - additional_wires=self.label_wires, + additional_bits=np.concatenate((self.train_data, self.label_indices), axis=1), + additional_wires=self.train_wires + self.label_wires, unclean_wires=unclean_wires, ) @@ -105,10 +110,13 @@ def get_label_from_samples(self, samples: List[List[int]]) -> int: is equal to |0>. """ label_probs = np.zeros(len(self.unique_labels)) + counts = np.zeros(len(self.unique_labels)) for sample in samples: label = bitlist_to_int(sample[1:]) if sample[0] == 0 and label < len(label_probs): label_probs[label] += 1 + if label < len(label_probs): + counts[label] += 1 return self.unique_labels[label_probs.argmax()] def get_quantum_circuit(self, x: np.ndarray) -> Callable[[], None]: @@ -128,7 +136,7 @@ def get_quantum_circuit(self, x: np.ndarray) -> Callable[[], None]: def circuit(): self.qam.circuit() for x_, train_wire in zip(x, self.train_wires): - if x_ == 0: + if x_ == 1: qml.PauliX((train_wire,)) for train_wire in self.train_wires: # QAM ancilla wires are 0 after QAM -> use one of those wires @@ -147,8 +155,9 @@ def label_point(self, x: np.ndarray) -> int: @staticmethod def get_necessary_wires( train_data: np.ndarray, train_labels: np.ndarray - ) -> Tuple[int, int, int]: + ) -> Tuple[int, int, int, int]: return ( + int(np.ceil(np.log2(train_data.shape[0]))), len(train_data[0]), ceil_log2(len(set(train_labels))), max(len(train_data[0]), 2), From 5add5881dd7a6ade37fecca221b2ddbfb344c1fe Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 29 May 2023 13:34:54 +0200 Subject: [PATCH 06/16] Ruan can now handle duplicate data. Fixed utils and fixed InputParameters --- .../backend/parzen_windows/parzen_window.py | 11 +++++++-- .../parzen_windows/ruan_parzen_window.py | 23 ++++++++++++++----- .../quantum_parzen_window/backend/utils.py | 7 +++++- plugins/quantum_parzen_window/schemas.py | 2 +- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/plugins/quantum_parzen_window/backend/parzen_windows/parzen_window.py b/plugins/quantum_parzen_window/backend/parzen_windows/parzen_window.py index 9249b2014..0231c2082 100644 --- a/plugins/quantum_parzen_window/backend/parzen_windows/parzen_window.py +++ b/plugins/quantum_parzen_window/backend/parzen_windows/parzen_window.py @@ -81,10 +81,17 @@ def get_parzen_window( train_labels=train_labels, ) if use_access_wires: - wires[2] = wires[2] + access_wires + wires[3] = wires[3] + access_wires return RuanParzenWindow( - train_data, train_labels, window_size, wires[0], wires[1], wires[2], None + train_data, + train_labels, + window_size, + wires[0], + wires[1], + wires[2], + wires[3], + None, ), count_wires(wires) def check_and_get_qubits( diff --git a/plugins/quantum_parzen_window/backend/parzen_windows/ruan_parzen_window.py b/plugins/quantum_parzen_window/backend/parzen_windows/ruan_parzen_window.py index d58f84f63..e2131078d 100644 --- a/plugins/quantum_parzen_window/backend/parzen_windows/ruan_parzen_window.py +++ b/plugins/quantum_parzen_window/backend/parzen_windows/ruan_parzen_window.py @@ -29,6 +29,7 @@ def __init__( train_data: np.ndarray, train_labels: np.ndarray, distance_threshold: float, + idx_wires: List[int], train_wires: List[int], label_wires: List[int], ancilla_wires: List[int], @@ -54,17 +55,21 @@ def __init__( self.label_indices = self.init_labels(train_labels) self.unclean_wires = [] if unclean_wires is None else unclean_wires + self.idx_wires = idx_wires self.train_wires = train_wires self.label_wires = label_wires self.ancilla_wires = ancilla_wires - wire_types = ["train", "label", "ancilla", "unclean"] + wire_types = ["idx", "train", "label", "ancilla", "unclean"] + num_idx_wires = int(np.ceil(np.log2(self.train_data.shape[0]))) num_wires = [ + num_idx_wires, self.train_data.shape[1], max(1, ceil_log2(len(self.unique_labels))), ceil_log2(self.train_data.shape[1]) + 4, ] error_msgs = [ + "the round up log2 of the number of points, i.e. ceil(log2(no. points)).", "the points' dimensionality.", "ceil(log2(no. of unique labels)) and greater or equal to 1.", "ceil(log2(the points' dimensionality)) + 4.", @@ -86,11 +91,16 @@ def __init__( ] # Any additional wires self.qam = QAM( - self.train_data, - self.train_wires, + np.array( + [ + int_to_bitlist(i, num_idx_wires) + for i in range(self.train_data.shape[0]) + ] + ), # The indices + self.idx_wires, self.ancilla_wires, - additional_bits=self.label_indices, - additional_wires=self.label_wires, + additional_bits=np.concatenate((self.train_data, self.label_indices), axis=1), + additional_wires=self.train_wires + self.label_wires, unclean_wires=self.unclean_wires, ) @@ -178,9 +188,10 @@ def label_point(self, x: np.ndarray) -> int: @staticmethod def get_necessary_wires( train_data: np.ndarray, train_labels: np.ndarray - ) -> Tuple[int, int, int]: + ) -> Tuple[int, int, int, int]: unique_labels = list(set(train_labels)) return ( + int(np.ceil(np.log2(train_data.shape[0]))), int(len(train_data[0])), max(1, ceil_log2(len(unique_labels))), ceil_log2(len(train_data[0])) + 4, diff --git a/plugins/quantum_parzen_window/backend/utils.py b/plugins/quantum_parzen_window/backend/utils.py index d9c3b3c2e..c301148f5 100644 --- a/plugins/quantum_parzen_window/backend/utils.py +++ b/plugins/quantum_parzen_window/backend/utils.py @@ -27,7 +27,7 @@ def bitlist_to_int(bitlist: List[int]) -> int: def int_to_bitlist(num, length: int): binary = bin(num)[2:] - result = [int(el) for el in reversed(binary)] + result = [int(el) for el in binary] if len(result) > length: raise ValueError( f"Binary representation of {num} needs at least {len(result)} bits, but only got {length}." @@ -40,5 +40,10 @@ def is_binary(data: np.ndarray) -> bool: return np.array_equal(data, data.astype(bool)) +def check_binary(data: np.ndarray, error_msg: str): + if not is_binary(data): + raise ValueError(error_msg) + + def ceil_log2(value: float) -> int: return int(np.ceil(np.log2(value))) diff --git a/plugins/quantum_parzen_window/schemas.py b/plugins/quantum_parzen_window/schemas.py index 2abd32662..b279ea8a2 100644 --- a/plugins/quantum_parzen_window/schemas.py +++ b/plugins/quantum_parzen_window/schemas.py @@ -45,7 +45,7 @@ class InputParameters: shots: int ibmq_token: str custom_backend: str - minimize_qubit_count = False + minimize_qubit_count: bool = False def __str__(self): variables = self.__dict__.copy() From fc432de5c4399428f52b7b0b1123b999ea569257 Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 29 May 2023 13:37:26 +0200 Subject: [PATCH 07/16] Changed order of quantum backends --- .../quantum_k_nearest_neighbours/backend/quantum_backends.py | 4 ++-- plugins/quantum_parzen_window/backend/quantum_backends.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/quantum_k_nearest_neighbours/backend/quantum_backends.py b/plugins/quantum_k_nearest_neighbours/backend/quantum_backends.py index 5de1ccc03..6d20668bc 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/quantum_backends.py +++ b/plugins/quantum_k_nearest_neighbours/backend/quantum_backends.py @@ -25,7 +25,7 @@ class QuantumBackends(enum.Enum): - custom_ibmq = "custom_ibmq" + pennylane_default = "pennylane_default" aer_statevector_simulator = "aer_statevector_simulator" aer_qasm_simulator = "aer_qasm_simulator" ibmq_qasm_simulator = "ibmq_qasm_simulator" @@ -36,7 +36,7 @@ class QuantumBackends(enum.Enum): ibmq_belem = "ibmq_belem" ibmq_lima = "ibmq_lima" ibmq_armonk = "ibmq_armonk" - pennylane_default = "pennylane_default" + custom_ibmq = "custom_ibmq" def get_max_num_qbits( self, diff --git a/plugins/quantum_parzen_window/backend/quantum_backends.py b/plugins/quantum_parzen_window/backend/quantum_backends.py index 5de1ccc03..6d20668bc 100644 --- a/plugins/quantum_parzen_window/backend/quantum_backends.py +++ b/plugins/quantum_parzen_window/backend/quantum_backends.py @@ -25,7 +25,7 @@ class QuantumBackends(enum.Enum): - custom_ibmq = "custom_ibmq" + pennylane_default = "pennylane_default" aer_statevector_simulator = "aer_statevector_simulator" aer_qasm_simulator = "aer_qasm_simulator" ibmq_qasm_simulator = "ibmq_qasm_simulator" @@ -36,7 +36,7 @@ class QuantumBackends(enum.Enum): ibmq_belem = "ibmq_belem" ibmq_lima = "ibmq_lima" ibmq_armonk = "ibmq_armonk" - pennylane_default = "pennylane_default" + custom_ibmq = "custom_ibmq" def get_max_num_qbits( self, From fc1971da3b4afeb5a1279a00b77cf646643520d6 Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 29 May 2023 13:53:25 +0200 Subject: [PATCH 08/16] Added option to not produce a visualization --- .../quantum_k_nearest_neighbours/schemas.py | 10 +++++++ plugins/quantum_k_nearest_neighbours/tasks.py | 27 ++++++++++--------- plugins/quantum_parzen_window/schemas.py | 10 +++++++ plugins/quantum_parzen_window/tasks.py | 23 +++++++++------- 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/plugins/quantum_k_nearest_neighbours/schemas.py b/plugins/quantum_k_nearest_neighbours/schemas.py index 722f29de6..e7178a41c 100644 --- a/plugins/quantum_k_nearest_neighbours/schemas.py +++ b/plugins/quantum_k_nearest_neighbours/schemas.py @@ -49,6 +49,7 @@ class InputParameters: custom_backend: str resolution: int minimize_qubit_count: bool = False + visualize: bool = False def __str__(self): variables = self.__dict__.copy() @@ -201,6 +202,15 @@ class InputParametersSchema(FrontendFormBaseSchema): "input_type": "text", }, ) + visualize = ma.fields.Boolean( + required=False, + allow_none=False, + metadata={ + "label": "Visualize", + "description": "Plot the decision boundary for the trained classifier.", + "input_type": "checkbox", + }, + ) resolution = ma.fields.Integer( required=False, allow_none=False, diff --git a/plugins/quantum_k_nearest_neighbours/tasks.py b/plugins/quantum_k_nearest_neighbours/tasks.py index 182148173..bb2e12567 100644 --- a/plugins/quantum_k_nearest_neighbours/tasks.py +++ b/plugins/quantum_k_nearest_neighbours/tasks.py @@ -157,6 +157,7 @@ def calculation_task(self, db_id: int) -> str: ibmq_token = input_params.ibmq_token custom_backend = input_params.custom_backend resolution = input_params.resolution + visualize = input_params.visualize # Log information about the input parameters TASK_LOGGER.info(f"Loaded input parameters from db: {str(input_params)}") @@ -240,18 +241,20 @@ def calculation_task(self, db_id: int) -> str: if not qknn.heatmap_meaningful(): resolution = 0 - fig = plot_data( - train_data, - train_id_to_idx, - train_labels, - test_data, - test_id_to_idx, - predictions, - resolution=resolution, - predictor=qknn.label_points, - title=plot_title, - label_to_int=label_to_int, - ) + fig = None + if visualize: + fig = plot_data( + train_data, + train_id_to_idx, + train_labels, + test_data, + test_id_to_idx, + predictions, + resolution=resolution, + predictor=qknn.label_points, + title=plot_title, + label_to_int=label_to_int, + ) # Output the data with SpooledTemporaryFile(mode="w") as output: diff --git a/plugins/quantum_parzen_window/schemas.py b/plugins/quantum_parzen_window/schemas.py index b279ea8a2..cb085021d 100644 --- a/plugins/quantum_parzen_window/schemas.py +++ b/plugins/quantum_parzen_window/schemas.py @@ -46,6 +46,7 @@ class InputParameters: ibmq_token: str custom_backend: str minimize_qubit_count: bool = False + visualize: bool = False def __str__(self): variables = self.__dict__.copy() @@ -169,6 +170,15 @@ class InputParametersSchema(FrontendFormBaseSchema): "input_type": "text", }, ) + visualize = ma.fields.Boolean( + required=False, + allow_none=False, + metadata={ + "label": "Visualize", + "description": "Plot the decision boundary for the trained classifier.", + "input_type": "checkbox", + }, + ) @post_load def make_input_params(self, data, **kwargs) -> InputParameters: diff --git a/plugins/quantum_parzen_window/tasks.py b/plugins/quantum_parzen_window/tasks.py index cf306d5c0..e9edfbfb5 100644 --- a/plugins/quantum_parzen_window/tasks.py +++ b/plugins/quantum_parzen_window/tasks.py @@ -154,6 +154,7 @@ def calculation_task(self, db_id: int) -> str: shots = input_params.shots ibmq_token = input_params.ibmq_token custom_backend = input_params.custom_backend + visualize = input_params.visualize # Log information about the input parameters TASK_LOGGER.info(f"Loaded input parameters from db: {str(input_params)}") @@ -232,16 +233,18 @@ def calculation_task(self, db_id: int) -> str: ) # Create plot - fig = plot_data( - train_data, - train_id_to_idx, - train_labels, - test_data, - test_id_to_idx, - predictions, - title=plot_title, - label_to_int=label_to_int, - ) + fig = None + if visualize: + fig = plot_data( + train_data, + train_id_to_idx, + train_labels, + test_data, + test_id_to_idx, + predictions, + title=plot_title, + label_to_int=label_to_int, + ) # Output the data with SpooledTemporaryFile(mode="w") as output: From 7a5b3abdcb97221ac57ccbf5770079ccd5aef31a Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 29 May 2023 14:12:46 +0200 Subject: [PATCH 09/16] Updated frontend.js --- .../quantum_k_nearest_neighbours/frontend.js | 30 +++++++++++++++ plugins/quantum_parzen_window/frontend.js | 38 +++++++++++++++++++ plugins/quantum_parzen_window/routes.py | 9 +++++ 3 files changed, 77 insertions(+) create mode 100644 plugins/quantum_parzen_window/frontend.js diff --git a/plugins/quantum_k_nearest_neighbours/frontend.js b/plugins/quantum_k_nearest_neighbours/frontend.js index c4be70dbc..2893ffccf 100644 --- a/plugins/quantum_k_nearest_neighbours/frontend.js +++ b/plugins/quantum_k_nearest_neighbours/frontend.js @@ -18,11 +18,16 @@ var qknn_type_value = document.getElementById("variant"); var k_value = document.getElementById("k"); var exp_itr_value = document.getElementById("exp_itr"); var slack_value = document.getElementById("slack"); +var visualize_value = document.getElementById("visualize"); +var backend_value = document.getElementById("backend"); // If a vairable ends with _vis, it's the parentNode's parentNode and we can set the visibility var k_vis = k_value.parentNode.parentNode; var exp_itr_vis = exp_itr_value.parentNode.parentNode; var slack_vis = slack_value.parentNode.parentNode; +var resolution_vis = document.getElementById("resolution").parentNode.parentNode; +var ibmq_token_vis = document.getElementById("ibmq_token").parentNode.parentNode; +var custom_backend_vis = document.getElementById("custom_backend").parentNode.parentNode; function set_default_values() { @@ -58,6 +63,31 @@ function qknn_type_change(reset_values=true) { } } + +function visualize_change(){ + resolution_vis.style.display = "none"; + if (visualize_value.value === true) { + resolution_vis.style.display = "block"; + } +} + + +function backend_change() { + ibmq_token_vis.style.display = 'none'; + custom_backend_vis.style.display = 'none'; + if (backend_value.value.startsWith("ibmq") || backend_value.value === "aer_qasm_simulator") { + ibmq_token_vis.style.display = 'block'; + custom_backend_vis.style.display = 'none'; + } else if (backend_value.value === "custom_ibmq") { + ibmq_token_vis.style.display = 'block'; + custom_backend_vis.style.display = 'block'; + } +} + qknn_type_change(false); +visualize_change(); +backend_change(); qknn_type_value.addEventListener("change", qknn_type_change); +visualize_value.addEventListener("change", visualize_change); +backend_value.addEventListener("change", backend_change); diff --git a/plugins/quantum_parzen_window/frontend.js b/plugins/quantum_parzen_window/frontend.js new file mode 100644 index 000000000..1fb4ec958 --- /dev/null +++ b/plugins/quantum_parzen_window/frontend.js @@ -0,0 +1,38 @@ +// Copyright 2023 QHAna plugin runner contributors. +// +// 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. + +// Long block of just gathering elements +// If a variable ends with _value, it's the element itself and the value can be retrieved or set +var backend_value = document.getElementById("backend"); + +// If a vairable ends with _vis, it's the parentNode's parentNode and we can set the visibility +var ibmq_token_vis = document.getElementById("ibmq_token").parentNode.parentNode; +var custom_backend_vis = document.getElementById("custom_backend").parentNode.parentNode; + + +function backend_change() { + ibmq_token_vis.style.display = 'none'; + custom_backend_vis.style.display = 'none'; + if (backend_value.value.startsWith("ibmq") || backend_value.value === "aer_qasm_simulator") { + ibmq_token_vis.style.display = 'block'; + custom_backend_vis.style.display = 'none'; + } else if (backend_value.value === "custom_ibmq") { + ibmq_token_vis.style.display = 'block'; + custom_backend_vis.style.display = 'block'; + } +} + +backend_change(); + +backend_value.addEventListener("change", backend_change); diff --git a/plugins/quantum_parzen_window/routes.py b/plugins/quantum_parzen_window/routes.py index 925bfa194..d01720254 100644 --- a/plugins/quantum_parzen_window/routes.py +++ b/plugins/quantum_parzen_window/routes.py @@ -16,7 +16,10 @@ from http import HTTPStatus from typing import Mapping +from pathlib import Path + from celery.canvas import chain +from flask import send_file from flask import Response from flask import redirect from flask.globals import request @@ -191,10 +194,16 @@ def render(self, data: Mapping, errors: dict): values=data_dict, errors=errors, process=url_for(f"{QParzenWindow_BLP.name}.CalcView"), + frontendjs=url_for(f"{QParzenWindow_BLP.name}.get_frontend_js"), ) ) +@QParzenWindow_BLP.route("/ui/frontend_js/") +def get_frontend_js(): + return send_file(Path(__file__).parent / "frontend.js", mimetype="text/javascript") + + @QParzenWindow_BLP.route("/process/") class CalcView(MethodView): """Start a long running processing task.""" From dd2fcf4f3f68219183f9b744912bc030ce898648 Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 29 May 2023 21:40:06 +0200 Subject: [PATCH 10/16] Removed prints and unnecessary function --- .../backend/qknns/simpleQkNN.py | 3 --- plugins/quantum_k_nearest_neighbours/backend/utils.py | 6 ------ plugins/quantum_parzen_window/tasks.py | 1 - 3 files changed, 10 deletions(-) diff --git a/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py b/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py index 65263a5ad..a40bcc9d0 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py +++ b/plugins/quantum_k_nearest_neighbours/backend/qknns/simpleQkNN.py @@ -52,15 +52,12 @@ def label_point(self, x: np.ndarray) -> int: new_label = np.bincount(self.train_labels).argmax() else: distances = np.array(self.calculate_distances(x)) # Get distances - print(f"distances: {distances}") indices = np.argpartition(distances, self.k)[ : self.k ] # Get k smallest values - print(f"{self.k} indices with smallest value: {indices}") counts = Counter( self.train_labels[indices] ) # Count occurrences of labels in k smallest values - print(f"label counts: {counts}") new_label = max(counts, key=counts.get) # Get most frequent label return new_label diff --git a/plugins/quantum_k_nearest_neighbours/backend/utils.py b/plugins/quantum_k_nearest_neighbours/backend/utils.py index 79e115924..c301148f5 100644 --- a/plugins/quantum_k_nearest_neighbours/backend/utils.py +++ b/plugins/quantum_k_nearest_neighbours/backend/utils.py @@ -47,9 +47,3 @@ def check_binary(data: np.ndarray, error_msg: str): def ceil_log2(value: float) -> int: return int(np.ceil(np.log2(value))) - - -def check_for_duplicates(data: np.ndarray, error_msg: str): - print(f"Checking the following data for duplicates:\n{data}") - if len(np.unique(data, axis=0)) != len(data): - raise ValueError(error_msg) diff --git a/plugins/quantum_parzen_window/tasks.py b/plugins/quantum_parzen_window/tasks.py index e9edfbfb5..8fd25ffa2 100644 --- a/plugins/quantum_parzen_window/tasks.py +++ b/plugins/quantum_parzen_window/tasks.py @@ -109,7 +109,6 @@ def get_label_arr( entity_labels = list(get_label_generator(entity_labels_url)) # Initialise label array - print(f"id_to_idx type: {type(id_to_idx)}\nid_to_idx: {id_to_idx}") labels = np.zeros(len(id_to_idx.keys()), dtype=int) if label_to_int is None: From 5c39e83ea3a8f0af2e6b772fbc55b86e95c70cbb Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 7 Aug 2023 11:14:35 +0200 Subject: [PATCH 11/16] Use custom template, instead of frontend.js --- .../quantum_k_nearest_neighbours/__init__.py | 1 + .../quantum_k_nearest_neighbours/frontend.js | 93 ------------------- .../quantum_k_nearest_neighbours/routes.py | 8 +- .../template.html | 87 +++++++++++++++++ 4 files changed, 89 insertions(+), 100 deletions(-) delete mode 100644 plugins/quantum_k_nearest_neighbours/frontend.js create mode 100644 plugins/quantum_k_nearest_neighbours/template.html diff --git a/plugins/quantum_k_nearest_neighbours/__init__.py b/plugins/quantum_k_nearest_neighbours/__init__.py index f8588ef2b..ace1275e5 100644 --- a/plugins/quantum_k_nearest_neighbours/__init__.py +++ b/plugins/quantum_k_nearest_neighbours/__init__.py @@ -28,6 +28,7 @@ _identifier, # blueprint name __name__, # module import name! description="Quantum k nearest neighbours plugin API.", + template_folder="", ) diff --git a/plugins/quantum_k_nearest_neighbours/frontend.js b/plugins/quantum_k_nearest_neighbours/frontend.js deleted file mode 100644 index 2893ffccf..000000000 --- a/plugins/quantum_k_nearest_neighbours/frontend.js +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2023 QHAna plugin runner contributors. -// -// 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. - -// Long block of just gathering elements -// If a variable ends with _value, it's the element itself and the value can be retrieved or set -var qknn_type_value = document.getElementById("variant"); -var k_value = document.getElementById("k"); -var exp_itr_value = document.getElementById("exp_itr"); -var slack_value = document.getElementById("slack"); -var visualize_value = document.getElementById("visualize"); -var backend_value = document.getElementById("backend"); - -// If a vairable ends with _vis, it's the parentNode's parentNode and we can set the visibility -var k_vis = k_value.parentNode.parentNode; -var exp_itr_vis = exp_itr_value.parentNode.parentNode; -var slack_vis = slack_value.parentNode.parentNode; -var resolution_vis = document.getElementById("resolution").parentNode.parentNode; -var ibmq_token_vis = document.getElementById("ibmq_token").parentNode.parentNode; -var custom_backend_vis = document.getElementById("custom_backend").parentNode.parentNode; - - -function set_default_values() { - exp_itr_value.value = "10"; - k_value = 1; - slack_value = 0.05; -} - - -function hide_all() { - exp_itr_vis.style.display = 'none'; - k_vis.style.display = 'none'; - slack_vis.style.display = 'none'; -} - - -function show_basheer_hamming() { - exp_itr_vis.style.display = 'block'; - slack_vis.style.display = 'block'; -} - - -function qknn_type_change(reset_values=true) { - hide_all(); - if (reset_values) { - set_default_values(); - } - if (qknn_type_value.value !== "schuld_qknn") { - k_vis.style.display = 'block'; - } - if (qknn_type_value.value === "basheer_hamming_qknn") { - show_basheer_hamming(); - } -} - - -function visualize_change(){ - resolution_vis.style.display = "none"; - if (visualize_value.value === true) { - resolution_vis.style.display = "block"; - } -} - - -function backend_change() { - ibmq_token_vis.style.display = 'none'; - custom_backend_vis.style.display = 'none'; - if (backend_value.value.startsWith("ibmq") || backend_value.value === "aer_qasm_simulator") { - ibmq_token_vis.style.display = 'block'; - custom_backend_vis.style.display = 'none'; - } else if (backend_value.value === "custom_ibmq") { - ibmq_token_vis.style.display = 'block'; - custom_backend_vis.style.display = 'block'; - } -} - -qknn_type_change(false); -visualize_change(); -backend_change(); - -qknn_type_value.addEventListener("change", qknn_type_change); -visualize_value.addEventListener("change", visualize_change); -backend_value.addEventListener("change", backend_change); diff --git a/plugins/quantum_k_nearest_neighbours/routes.py b/plugins/quantum_k_nearest_neighbours/routes.py index e76e320b9..99094fb1c 100644 --- a/plugins/quantum_k_nearest_neighbours/routes.py +++ b/plugins/quantum_k_nearest_neighbours/routes.py @@ -190,23 +190,17 @@ def render(self, data: Mapping, errors: dict): return Response( render_template( - "simple_template.html", + "template.html", name=QKNN.instance.name, version=QKNN.instance.version, schema=InputParametersSchema(), values=data_dict, errors=errors, process=url_for(f"{QKNN_BLP.name}.CalcView"), - frontendjs=url_for(f"{QKNN_BLP.name}.get_frontend_js"), ) ) -@QKNN_BLP.route("/ui/frontend_js/") -def get_frontend_js(): - return send_file(Path(__file__).parent / "frontend.js", mimetype="text/javascript") - - @QKNN_BLP.route("/process/") class CalcView(MethodView): """Start a long running processing task.""" diff --git a/plugins/quantum_k_nearest_neighbours/template.html b/plugins/quantum_k_nearest_neighbours/template.html new file mode 100644 index 000000000..efb73eb4f --- /dev/null +++ b/plugins/quantum_k_nearest_neighbours/template.html @@ -0,0 +1,87 @@ +{% extends "simple_template.html" %} + +{% block head %} + {{ super() }} +{% endblock head %} + +{% block script %} + + {{ super() }} +{% endblock script %} From e089f280a3c6b4c63d832f4c1bd3e16eac7f5379 Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 7 Aug 2023 12:04:28 +0200 Subject: [PATCH 12/16] Updated visualize_change in template --- .../quantum_k_nearest_neighbours/template.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/template.html b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/template.html index efb73eb4f..495acded3 100644 --- a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/template.html +++ b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/template.html @@ -57,7 +57,7 @@ function visualize_change(){ resolution_vis.style.display = "none"; - if (visualize_value.value === true) { + if (visualize_value.checked) { resolution_vis.style.display = "block"; } } From e9d45a3cf22ce14339e155750579433c40435475 Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 7 Aug 2023 12:05:11 +0200 Subject: [PATCH 13/16] Removed check_duplicates import in schuld_hamming. --- .../quantum_k_nearest_neighbours/backend/qknns/schuld_hamming.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/backend/qknns/schuld_hamming.py b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/backend/qknns/schuld_hamming.py index 04a7c5f29..3da25e4de 100644 --- a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/backend/qknns/schuld_hamming.py +++ b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/backend/qknns/schuld_hamming.py @@ -23,7 +23,6 @@ int_to_bitlist, check_binary, ceil_log2, - check_for_duplicates, ) from ..check_wires import check_wires_uniqueness, check_num_wires From 1fb8b1ca27930630aa254a4da5f63356953f0217 Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 7 Aug 2023 12:19:59 +0200 Subject: [PATCH 14/16] Updated quantum_parzen_window to use a custom template, instead of frontend.js --- .../quantum_parzen_window/__init__.py | 1 + .../quantum_parzen_window/frontend.js | 38 ------------------- .../quantum_parzen_window/routes.py | 8 +--- .../quantum_parzen_window/template.html | 34 +++++++++++++++++ 4 files changed, 36 insertions(+), 45 deletions(-) delete mode 100644 stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/frontend.js create mode 100644 stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/template.html diff --git a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/__init__.py b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/__init__.py index 76bd65e30..acb57a20a 100644 --- a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/__init__.py +++ b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/__init__.py @@ -28,6 +28,7 @@ _identifier, # blueprint name __name__, # module import name! description="Quantum parzen window plugin API.", + template_folder="", ) diff --git a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/frontend.js b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/frontend.js deleted file mode 100644 index 1fb4ec958..000000000 --- a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/frontend.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2023 QHAna plugin runner contributors. -// -// 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. - -// Long block of just gathering elements -// If a variable ends with _value, it's the element itself and the value can be retrieved or set -var backend_value = document.getElementById("backend"); - -// If a vairable ends with _vis, it's the parentNode's parentNode and we can set the visibility -var ibmq_token_vis = document.getElementById("ibmq_token").parentNode.parentNode; -var custom_backend_vis = document.getElementById("custom_backend").parentNode.parentNode; - - -function backend_change() { - ibmq_token_vis.style.display = 'none'; - custom_backend_vis.style.display = 'none'; - if (backend_value.value.startsWith("ibmq") || backend_value.value === "aer_qasm_simulator") { - ibmq_token_vis.style.display = 'block'; - custom_backend_vis.style.display = 'none'; - } else if (backend_value.value === "custom_ibmq") { - ibmq_token_vis.style.display = 'block'; - custom_backend_vis.style.display = 'block'; - } -} - -backend_change(); - -backend_value.addEventListener("change", backend_change); diff --git a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/routes.py b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/routes.py index d01720254..6a938a512 100644 --- a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/routes.py +++ b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/routes.py @@ -187,23 +187,17 @@ def render(self, data: Mapping, errors: dict): return Response( render_template( - "simple_template.html", + "template.html", name=QParzenWindow.instance.name, version=QParzenWindow.instance.version, schema=InputParametersSchema(), values=data_dict, errors=errors, process=url_for(f"{QParzenWindow_BLP.name}.CalcView"), - frontendjs=url_for(f"{QParzenWindow_BLP.name}.get_frontend_js"), ) ) -@QParzenWindow_BLP.route("/ui/frontend_js/") -def get_frontend_js(): - return send_file(Path(__file__).parent / "frontend.js", mimetype="text/javascript") - - @QParzenWindow_BLP.route("/process/") class CalcView(MethodView): """Start a long running processing task.""" diff --git a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/template.html b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/template.html new file mode 100644 index 000000000..a984df2d2 --- /dev/null +++ b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/template.html @@ -0,0 +1,34 @@ +{% extends "simple_template.html" %} + +{% block head %} + {{ super() }} +{% endblock head %} + +{% block script %} + + {{ super() }} +{% endblock script %} From 5751a95a6f68d555271351c4c88a36b7b3923b1a Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 7 Aug 2023 12:33:09 +0200 Subject: [PATCH 15/16] Changed default backend value --- .../pennylane_qiskit_ml/quantum_k_nearest_neighbours/routes.py | 2 +- .../pennylane_qiskit_ml/quantum_parzen_window/routes.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/routes.py b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/routes.py index 99094fb1c..cbd840687 100644 --- a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/routes.py +++ b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/routes.py @@ -173,7 +173,7 @@ def render(self, data: Mapping, errors: dict): fields["minimize_qubit_count"].data_key: False, fields["exp_itr"].data_key: 10, fields["slack"].data_key: 0.05, - fields["backend"].data_key: QuantumBackends.aer_statevector_simulator.value, + fields["backend"].data_key: QuantumBackends.pennylane_default.value, fields["shots"].data_key: 1024, fields["resolution"].data_key: 20, } diff --git a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/routes.py b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/routes.py index 6a938a512..96ca9a296 100644 --- a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/routes.py +++ b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/routes.py @@ -171,7 +171,7 @@ def render(self, data: Mapping, errors: dict): default_values = { fields["window_size"].data_key: 1, fields["minimize_qubit_count"].data_key: False, - fields["backend"].data_key: QuantumBackends.aer_statevector_simulator.value, + fields["backend"].data_key: QuantumBackends.pennylane_default.value, fields["shots"].data_key: 1024, } From d38ebeff733589c2814ad5bd6e0abd8874f0b10f Mon Sep 17 00:00:00 2001 From: BenediktRiegel Date: Mon, 7 Aug 2023 12:34:36 +0200 Subject: [PATCH 16/16] Updated version number --- .../quantum_k_nearest_neighbours/__init__.py | 2 +- .../pennylane_qiskit_ml/quantum_parzen_window/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/__init__.py b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/__init__.py index 0fbe65c36..1e29cb749 100644 --- a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/__init__.py +++ b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_k_nearest_neighbours/__init__.py @@ -20,7 +20,7 @@ from qhana_plugin_runner.util.plugins import plugin_identifier, QHAnaPluginBase _plugin_name = "quantum-k-nearest-neighbours" -__version__ = "v0.1.0" +__version__ = "v0.2.0" _identifier = plugin_identifier(_plugin_name, __version__) diff --git a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/__init__.py b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/__init__.py index acb57a20a..db3ba53c2 100644 --- a/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/__init__.py +++ b/stable_plugins/quantum_ml/pennylane_qiskit_ml/quantum_parzen_window/__init__.py @@ -20,7 +20,7 @@ from qhana_plugin_runner.util.plugins import plugin_identifier, QHAnaPluginBase _plugin_name = "quantum-parzen-window" -__version__ = "v0.1.0" +__version__ = "v0.2.0" _identifier = plugin_identifier(_plugin_name, __version__)