Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added max_circuits_per_job and removed deepcopy dependency of the quantum kernel trainer fixing #701 and #600 #772

Merged
merged 15 commits into from
Feb 29, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Updated documentation and format the style.
OkuyanBoga committed Feb 13, 2024
commit 145ec479e244b6ae8a87c1906252eaa02e3b73da
63 changes: 37 additions & 26 deletions qiskit_machine_learning/kernels/fidelity_quantum_kernel.py
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@ def __init__(
fidelity: BaseStateFidelity | None = None,
enforce_psd: bool = True,
evaluate_duplicates: str = "off_diagonal",
max_circuits_per_job: int = 300,
) -> None:
"""
Args:
@@ -73,6 +74,8 @@ def __init__(
- ``none`` when training the diagonal is set to `1` and if two identical samples
are found in the dataset the corresponding matrix element is set to `1`.
When inferring, matrix elements for identical samples are set to `1`.
max_circuits_per_job: Maximum number of circuits per job for the backend. Please
check the backend specifications. Use ``None`` for all entries per job. Default ``300``.
Raises:
ValueError: When unsupported value is passed to `evaluate_duplicates`.
"""
@@ -84,10 +87,10 @@ def __init__(
f"Unsupported value passed as evaluate_duplicates: {evaluate_duplicates}"
)
self._evaluate_duplicates = eval_duplicates

if fidelity is None:
fidelity = ComputeUncompute(sampler=Sampler())
self._fidelity = fidelity
self.max_circuits_per_job = max_circuits_per_job

def evaluate(self, x_vec: np.ndarray, y_vec: np.ndarray | None = None) -> np.ndarray:
x_vec, y_vec = self._validate_input(x_vec, y_vec)
@@ -207,37 +210,45 @@ def _get_symmetric_kernel_matrix(
return kernel_matrix

def _get_kernel_entries(
self, left_parameters: np.ndarray, right_parameters: np.ndarray, max_circuits_per_job: int = 300
self, left_parameters: np.ndarray, right_parameters: np.ndarray
) -> Sequence[float]:
"""
Gets kernel entries by executing the underlying fidelity instance and getting the results
back from the async job. The number of circuits per job is limited by the max_circuits_per_job parameter.
back from the async job.
"""
num_circuits = left_parameters.shape[0]
kernel_entries = []

# Determine the number of chunks needed
num_chunks = (num_circuits + max_circuits_per_job - 1) // max_circuits_per_job

for i in range(num_chunks):
# Determine the range of indices for this chunk
start_idx = i * max_circuits_per_job
end_idx = min((i + 1) * max_circuits_per_job, num_circuits)

# Extract the parameters for this chunk
chunk_left_parameters = left_parameters[start_idx:end_idx]
chunk_right_parameters = right_parameters[start_idx:end_idx]

# Execute this chunk
job = self._fidelity.run(
[self._feature_map] * (end_idx - start_idx),
[self._feature_map] * (end_idx - start_idx),
chunk_left_parameters,
chunk_right_parameters,
)

# Extend the kernel_entries list with the results from this chunk
kernel_entries.extend(job.result().fidelities)
# Check if it is trivial case, only identical samples
if num_circuits != 0:
if self.max_circuits_per_job is None:
job = self._fidelity.run(
[self._feature_map] * num_circuits,
[self._feature_map] * num_circuits,
left_parameters,
right_parameters,
)
kernel_entries = job.result().fidelities
else:
# Determine the number of chunks needed
num_chunks = (
num_circuits + self.max_circuits_per_job - 1
) // self.max_circuits_per_job
for i in range(num_chunks):
# Determine the range of indices for this chunk
start_idx = i * self.max_circuits_per_job
end_idx = min((i + 1) * self.max_circuits_per_job, num_circuits)
# Extract the parameters for this chunk
chunk_left_parameters = left_parameters[start_idx:end_idx]
chunk_right_parameters = right_parameters[start_idx:end_idx]
# Execute this chunk
job = self._fidelity.run(
[self._feature_map] * (end_idx - start_idx),
[self._feature_map] * (end_idx - start_idx),
chunk_left_parameters,
chunk_right_parameters,
)
# Extend the kernel_entries list with the results from this chunk
kernel_entries.extend(job.result().fidelities)
return kernel_entries

def _is_trivial(