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

Adding Response + cleaning up classically optimize #9

Merged
merged 14 commits into from
Feb 23, 2024
Merged
Prev Previous commit
Next Next commit
implement affine trans before fine-tuning
  • Loading branch information
jiaqileng committed Feb 13, 2024
commit 7dcb3a8fee64f31bb65e6ca9a684db4ec418885c
54 changes: 40 additions & 14 deletions src/qhdopt/qhd.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ def affine_transformation(self, x):
def jax_affine_transformation(self, x):
return jnp.array(self.scaling_factor) * x + jnp.array(self.lb)

def fun_eval(self, x):
"""
x is in the original box (non-normalized)
"""
x = x.astype(jnp.float32)
return self.lambda_numpy(*x)

def f_eval(self, x):
x = self.jax_affine_transformation(x.astype(jnp.float32))
return self.lambda_numpy(*x)
Expand All @@ -174,12 +181,12 @@ def validate_guesses_in_box(self, guesses):
for i in range(len(self.lb)):
lb = self.lb[i]
ub = self.lb[i] + self.scaling_factor[i]
assert ub > guess[i] > lb
assert ub >= guess[i] >= lb

def classically_optimize(self, shots=100, solver="TNC", initial_guesses=None):
self.generate_univariate_bivariate_repr()
if initial_guesses is None:
initial_guesses = np.random.rand(shots, self.dimension)
initial_guesses = np.random.rand(shots, self.dimension) # TBC
self.validate_guesses_in_box(initial_guesses)
f = lambda x: self.lambda_numpy(*x)
ub = [self.lb[i] + self.scaling_factor[i] for i in range(len(self.lb))]
Expand Down Expand Up @@ -229,14 +236,20 @@ def classically_optimize_helper(self, samples, bounds, solver, f):
minimizer = result.x
end_time = time.time()
post_processing_time = end_time - start_time

return opt_samples, minimizer, current_best, post_processing_time

def post_process(self):
if self.decoded_samples is None:
raise Exception("No results on record.")
samples = self.decoded_samples
solver = self.post_processing_method
bounds = Bounds(np.zeros(self.dimension), np.ones(self.dimension))
opt_samples, minimizer, current_best, post_processing_time = self.classically_optimize_helper(samples, bounds, solver, self.f_eval)

ub = [self.lb[i] + self.scaling_factor[i] for i in range(len(self.lb))]
bounds = Bounds(np.array(self.lb), np.array(ub))
opt_samples, minimizer, current_best, post_processing_time = self.classically_optimize_helper(samples, bounds, solver, self.fun_eval)
# bounds = Bounds(np.zeros(self.dimension), np.ones(self.dimension))
# opt_samples, minimizer, current_best, post_processing_time = self.classically_optimize_helper(samples, bounds, solver, self.f_eval)
self.post_processed_samples = opt_samples
self.info["post_processing_time"] = post_processing_time

Expand All @@ -249,8 +262,9 @@ def optimize(self, fine_tune=True, compile_only=False, verbose=0, samples=None):
return

start_time_decoding = time.time()
coarse_minimizer, coarse_minimum, self.decoded_samples = self.backend.decoder(raw_samples,
self.f_eval)
unit_box_coarse_minimizer, unit_box_coarse_minimum, self.unit_box_decoded_samples = self.backend.decoder(raw_samples, self.f_eval)
coarse_minimizer, coarse_minimum, self.decoded_samples = self.affine_mapping(unit_box_coarse_minimizer, unit_box_coarse_minimum, self.unit_box_decoded_samples)

if samples is not None:
self.decoded_samples = samples
end_time_decoding = time.time()
Expand All @@ -262,19 +276,34 @@ def optimize(self, fine_tune=True, compile_only=False, verbose=0, samples=None):
end_time_finetuning = time.time()
self.info["refined_minimum"] = refined_minimum
self.info["fine_tuning_time"] = end_time_finetuning - start_time_finetuning
qhd_response = Response(self.decoded_samples, coarse_minimum, coarse_minimizer,
self.jax_affine_transformation, self.info,
qhd_response = Response(self.info,
self.unit_box_decoded_samples, unit_box_coarse_minimum, unit_box_coarse_minimizer,
self.decoded_samples, coarse_minimum, coarse_minimizer,
self.post_processed_samples, refined_minimum, refined_minimizer)
else:
qhd_response = Response(self.decoded_samples, coarse_minimum, coarse_minimizer,
self.jax_affine_transformation, self.info)
qhd_response = Response(self.info,
self.unit_box_decoded_samples, unit_box_coarse_minimum, unit_box_coarse_minimizer,
self.decoded_samples, coarse_minimum, coarse_minimizer)

if verbose > 0:
qhd_response.print_time_info()
qhd_response.print_solver_info()
self.response = qhd_response

return qhd_response

def affine_mapping(self, minimizer, minimum, samples):
original_minimizer = self.affine_transformation(minimizer)
original_minimum = minimum
original_samples = []

for k in range(len(samples)):
if samples[k] is None:
continue
original_samples.append(self.affine_transformation(samples[k]))

return original_minimizer, original_minimum, original_samples

def calc_h_and_J(self):
if not isinstance(self.backend, dwave_backend.DWaveBackend):
raise Exception(
Expand All @@ -290,10 +319,7 @@ def get_solution(self, var=None):
- a list of Symbols (return a list of the values of the symbols)
"""

if self.info["fine_tune_status"]:
values = self.info["refined_minimizer_affined"]
else:
values = self.info["coarse_minimizer_affined"]
values = self.response.minimizer

if var is None:
return values
Expand Down
31 changes: 19 additions & 12 deletions src/qhdopt/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@


class Response:
def __init__(self, coarse_samples, coarse_minimum, coarse_minimizer, affine_trans, info,
def __init__(self, info,
unit_box_coarse_samples, unit_box_coarse_minimum, unit_box_coarse_minimizer,
coarse_samples, coarse_minimum, coarse_minimizer,
refined_samples=None, refined_minimum=None, refined_minimizer=None):
self.unit_box_coarse_samples = coarse_samples
self.unit_box_coarse_samples = unit_box_coarse_samples
self.unit_box_coarse_minimum = unit_box_coarse_minimum
self.unit_box_coarse_minimizer = unit_box_coarse_minimizer
self.coarse_samples = coarse_samples
self.coarse_minimum = coarse_minimum
self.unit_box_coarse_minimizer = coarse_minimizer
self.affine_trans = affine_trans
self.info = info
self.unit_box_refined_samples = refined_samples
self.unit_box_refined_minimizer = refined_minimizer
self.coarse_minimizer = coarse_minimizer
self.refined_samples = refined_samples
self.refined_minimum = refined_minimum
self.coarse_minimizer = self.affine_trans(self.unit_box_coarse_minimizer)

self.refined_minimizer = refined_minimizer
self.minimizer = self.refined_minimizer if refined_minimizer is not None else self.coarse_minimizer
self.minimum = self.refined_minimum if refined_minimum is not None else self.coarse_minimum
self.unit_box_minimizer = self.unit_box_refined_minimizer if self.unit_box_refined_minimizer is not None else self.unit_box_coarse_minimizer
self.info = info

'''
@property
def coarse_samples(self):
return [self.affine_trans(sample) for sample in self.unit_box_coarse_samples]
Expand All @@ -29,6 +33,8 @@ def samples(self):
def minimizer(self):
minimizer = self.unit_box_refined_minimizer if self.unit_box_refined_minimizer is not None else self.unit_box_coarse_minimizer
return self.affine_trans(minimizer)
'''


def print_solver_info(self):
print("* Coarse solution")
Expand All @@ -37,11 +43,11 @@ def print_solver_info(self):
print("Minimum:", self.coarse_minimum)
print()

if self.unit_box_refined_samples is not None:
if self.refined_samples is not None:
print("* Fine-tuned solution")
print("Minimizer:", self.minimizer)
print("Minimum:", self.minimum)
print("Unit Box Minimizer:", self.unit_box_refined_minimizer)
# print("Unit Box Minimizer:", self.unit_box_refined_minimizer)
print()

def print_time_info(self):
Expand All @@ -57,3 +63,4 @@ def print_time_info(self):
total_runtime += self.info['fine_tuning_time']

print(f"* Total time: {total_runtime:.3f} s")
print()