Skip to content

Commit

Permalink
fix precommit
Browse files Browse the repository at this point in the history
  • Loading branch information
donghufeng committed Dec 2, 2024
1 parent 01676b6 commit f1cff53
Show file tree
Hide file tree
Showing 28 changed files with 282 additions and 227 deletions.
5 changes: 1 addition & 4 deletions examples/quantum_rl/misc/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,14 @@ def get_obs_policy(obsw, beta):
"""
Output the final policy.
"""
process = tf.keras.Sequential(
return tf.keras.Sequential(
[
Alternating_(obsw),
tf.keras.layers.Lambda(lambda x: x * beta),
tf.keras.layers.Softmax(),
],
name="obs_policy",
)
return process


def get_height(position):
Expand Down Expand Up @@ -172,7 +171,6 @@ def gather_episodes(
while not all(done):
unfinished_ids = [i for i in range(n_episodes) if not done[i]]
normalized_states = [s / state_bounds for i, s in enumerate(states) if not done[i]]
# height = [get_height(s[0]) for i, s in enumerate(states) if not done[i]]

for i, state in zip(unfinished_ids, normalized_states):
trajectories[i]["states"].append(state)
Expand All @@ -187,7 +185,6 @@ def gather_episodes(
circuit, _, _ = generate_circuit(qubits, genotype, newtheta, newlamda, states.numpy()[0])
taskid, expectation = get_quafu_exp(circuit, n_qubits, backend_quafu, shots)
tasklist.append(taskid)
# print('gather_episodes_exp:', expectation)

obsw = model.get_layer("observables-policy").get_weights()[0]
obspolicy = get_obs_policy(obsw, beta)
Expand Down
33 changes: 15 additions & 18 deletions examples/quantum_rl/models/quantum_models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import cirq
import models.quantum_genotypes as genotypes
import numpy as np
import tensorflow as tf
import tensorflow_quantum as tfq
from models.quantum_operations import *
from models.quantum_operations import OPS


def generate_circuit(qubits, genotype, newtheta=None, newlamda=None, state=None):
Expand All @@ -13,37 +12,37 @@ def generate_circuit(qubits, genotype, newtheta=None, newlamda=None, state=None)
op_entangle, pos_entangle = zip(*genotype.entangle)
op_measure, pos_measure = zip(*genotype.measure)

dict = {}
dict_data = {}
for name, pos in zip(op_vpqc, pos_vpqc):
dict[pos] = name
dict_data[pos] = name
for name, pos in zip(op_dpqc, pos_dpqc):
dict[pos] = name
dict_data[pos] = name
for name, pos in zip(op_entangle, pos_entangle):
dict[pos] = name
dict_data[pos] = name
for name, pos in zip(op_measure, pos_measure):
dict[pos] = name
length = len(dict)
dict_data[pos] = name
length = len(dict_data)

circuit = cirq.Circuit()
params = []
inputs = []
p_count = 0
i_count = 0
for i in range(length):
if dict[i] == "variationalPQC":
cir, pa = OPS[dict[i]](qubits, p_count, newtheta)
if dict_data[i] == "variationalPQC":
cir, pa = OPS[dict_data[i]](qubits, p_count, newtheta)
circuit += cir
params += pa
p_count += 1
elif dict[i] == "dataencodingPQC":
cir, inp = OPS[dict[i]](qubits, i, i_count, newlamda, state)
elif dict_data[i] == "dataencodingPQC":
cir, inp = OPS[dict_data[i]](qubits, i, i_count, newlamda, state)
circuit += cir
inputs += inp
i_count += 1
elif dict[i] == "entanglement":
cir = OPS[dict[i]](qubits)
elif dict_data[i] == "entanglement":
cir = OPS[dict_data[i]](qubits)
circuit += cir
elif dict[i] == "measurement":
elif dict_data[i] == "measurement":
pass
else:
raise NameError("Unknown quantum genotype operation")
Expand Down Expand Up @@ -163,6 +162,4 @@ def generate_model_policy(qubits, genotype, n_actions, beta, observables, env):
name="observables-policy",
)
policy = process(nsganet_pqc)
model = tf.keras.Model(inputs=[input_tensor], outputs=policy)

return model
return tf.keras.Model(inputs=[input_tensor], outputs=policy)
8 changes: 3 additions & 5 deletions examples/quantum_rl/models/quantum_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ def entangling_layer(qubits):
Return a layer of CZ entangling gates on `qubits` (arranged in a circular topology).
Note: for lower depth of compiled circuits, you can only choose adjacent CZ
"""
cz_ops = [cirq.CZ(q0, q1) for q0, q1 in zip(qubits, qubits[1:])]
# cz_ops += ([cirq.CZ(qubits[0], qubits[-1])] if len(qubits) != 2 else [])
return cz_ops
return [cirq.CZ(q0, q1) for q0, q1 in zip(qubits, qubits[1:])]


def generate_vpqc(qubits, position, params=None):
Expand All @@ -40,7 +38,7 @@ def generate_vpqc(qubits, position, params=None):
n_qubits = len(qubits)

# Sympy symbols or load parameters for variational angles
if params == None:
if params is None:
params = sympy.symbols(f"theta({3*position*n_qubits}:{3*(position+1)*n_qubits})")
else:
params = params[3 * position * n_qubits : 3 * (position + 1) * n_qubits]
Expand All @@ -61,7 +59,7 @@ def generate_dpqc(qubits, position, count, params=None, state=None):
n_qubits = len(qubits)

# Sympy symbols or load parameters for encoding angles
if params == None:
if params is None:
inputs = sympy.symbols(f"x{position}" + f"_(0:{n_qubits})")
else:
inputs = params[count * n_qubits : (count + 1) * n_qubits]
Expand Down
57 changes: 28 additions & 29 deletions examples/quantum_rl/search/nsganet.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,44 +133,43 @@ def calc_crowding_distance(F):

if n_points <= 2:
return np.full(n_points, infinity)
else:
# sort each column and get index
I = np.argsort(F, axis=0, kind="mergesort")
# sort each column and get index
I = np.argsort(F, axis=0, kind="mergesort")

# now really sort the whole array
F = F[I, np.arange(n_obj)]
# now really sort the whole array
F = F[I, np.arange(n_obj)]

# get the distance to the last element in sorted list and replace zeros with actual values
dist = np.concatenate([F, np.full((1, n_obj), np.inf)]) - np.concatenate([np.full((1, n_obj), -np.inf), F])
# get the distance to the last element in sorted list and replace zeros with actual values
dist = np.concatenate([F, np.full((1, n_obj), np.inf)]) - np.concatenate([np.full((1, n_obj), -np.inf), F])

index_dist_is_zero = np.where(dist == 0)
index_dist_is_zero = np.where(dist == 0)

dist_to_last = np.copy(dist)
for i, j in zip(*index_dist_is_zero):
dist_to_last[i, j] = dist_to_last[i - 1, j]
dist_to_last = np.copy(dist)
for i, j in zip(*index_dist_is_zero):
dist_to_last[i, j] = dist_to_last[i - 1, j]

dist_to_next = np.copy(dist)
for i, j in reversed(list(zip(*index_dist_is_zero))):
dist_to_next[i, j] = dist_to_next[i + 1, j]
dist_to_next = np.copy(dist)
for i, j in reversed(list(zip(*index_dist_is_zero))):
dist_to_next[i, j] = dist_to_next[i + 1, j]

# normalize all the distances
norm = np.max(F, axis=0) - np.min(F, axis=0)
norm[norm == 0] = np.nan
dist_to_last, dist_to_next = dist_to_last[:-1] / norm, dist_to_next[1:] / norm
# normalize all the distances
norm = np.max(F, axis=0) - np.min(F, axis=0)
norm[norm == 0] = np.nan
dist_to_last, dist_to_next = dist_to_last[:-1] / norm, dist_to_next[1:] / norm

# if we divided by zero because all values in one columns are equal replace by none
dist_to_last[np.isnan(dist_to_last)] = 0.0
dist_to_next[np.isnan(dist_to_next)] = 0.0
# if we divided by zero because all values in one columns are equal replace by none
dist_to_last[np.isnan(dist_to_last)] = 0.0
dist_to_next[np.isnan(dist_to_next)] = 0.0

# sum up the distance to next and last and norm by objectives - also reorder from sorted list
J = np.argsort(I, axis=0)
crowding = (
np.sum(
dist_to_last[J, np.arange(n_obj)] + dist_to_next[J, np.arange(n_obj)],
axis=1,
)
/ n_obj
# sum up the distance to next and last and norm by objectives - also reorder from sorted list
J = np.argsort(I, axis=0)
crowding = (
np.sum(
dist_to_last[J, np.arange(n_obj)] + dist_to_next[J, np.arange(n_obj)],
axis=1,
)
/ n_obj
)

# replace infinity with a large number
crowding[np.isinf(crowding)] = infinity
Expand Down
4 changes: 1 addition & 3 deletions examples/quantum_rl/search/quantum_evolution_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ def _evaluate(self, x, out, *args, **kwargs):
def do_every_generations(algorithm):
"""Store statistic information of every generation."""
gen = algorithm.n_gen
pop_var = algorithm.pop.get("X")
pop_obj = algorithm.pop.get("F")

# report generation info to files
Expand Down Expand Up @@ -177,14 +176,13 @@ def main(qubits, n_actions, observables):
# configure the nsga-net method
method = engine.nsganet(pop_size=args.pop_size, n_offsprings=args.n_offspring, eliminate_duplicates=True)

res = minimize(
return minimize(
problem,
method,
callback=do_every_generations,
termination=("n_gen", args.n_gens),
)

return


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion examples/quantum_rl/search/quantum_train_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,6 @@ def reinforce_update(states, actions, returns, model):

if avg_rewards >= 500.0 and env_name == "CartPole-v1":
break
elif avg_rewards >= -110 and env_name == "MountainCar-v0":
if avg_rewards >= -110 and env_name == "MountainCar-v0":
break
return episode_reward_history
24 changes: 0 additions & 24 deletions examples/quantum_rl/validation/quantum_train.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
parser.add_argument("--save", type=str, default="qEXP-quafu18_6", help="experiment name")
parser.add_argument("--batch_size", type=int, default=1, help="batch size")
parser.add_argument("--n_episodes", type=int, default=100, help="the number of episodes")
# parser.add_argument('--infer_episodes', type=int, default=5, help='the number of infer episodes')
parser.add_argument("--gamma", type=float, default=1.0, help="discount parameter")
parser.add_argument("--env_name", type=str, default="CartPole-v1", help="environment name")
parser.add_argument(
Expand Down Expand Up @@ -171,29 +170,6 @@ def reinforce_update(states, actions, returns, logits2, model):
break
return episode_reward_history


# def infer(model):
# episode_reward_history = []
# for batch in range(args.infer_episodes // args.batch_size):
# # Gather episodes
# episodes = gather_episodes(args.state_bounds, args.n_actions, model, args.batch_size, args.env_name, qubits, genotype)

# # Group states, actions and returns in numpy arrays
# rewards = [ep['rewards'] for ep in episodes]

# # Store collected rewards
# for ep_rwds in rewards:
# episode_reward_history.append(np.sum(ep_rwds))

# avg_rewards = np.mean(episode_reward_history[-10:])

# logging.info('valid finished episode: %f', (batch + 1) * args.batch_size)
# logging.info('valid average rewards: %f', avg_rewards)

# if avg_rewards >= 500.0:
# break
# return episode_reward_history

if __name__ == "__main__":
qubits = cirq.GridQubit.rect(1, args.n_qubits)
genotype = eval("genotypes.%s" % args.arch)
Expand Down
11 changes: 11 additions & 0 deletions quafu/algorithms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,14 @@
from .templates.amplitude import AmplitudeEmbedding
from .templates.angle import AngleEmbedding
from .templates.basic_entangle import BasicEntangleLayers

__all__ = [
"AmplitudeEmbedding",
"AngleEmbedding",
"BasicEntangleLayers",
"AlterLayeredAnsatz",
"QAOAAnsatz",
"QuantumNeuralNetwork",
"Estimator",
"Hamiltonian",
]
5 changes: 0 additions & 5 deletions quafu/algorithms/estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,6 @@ def _measure_obs(self, qc: QuantumCircuit, measure_base: Optional[List] = None)

def _run_simulation(self, observables: Hamiltonian):
"""Run using quafu simulator"""
# sim_state = simulate(self._circ).get_statevector()
# expectation = np.matmul(
# np.matmul(sim_state.conj().T, observables.get_matrix()), sim_state
# ).real
# return expectation
return execute_circuit(self._circ, observables)

def clear_cache(self):
Expand Down
10 changes: 10 additions & 0 deletions quafu/algorithms/gradients/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,13 @@
from .gradiant import grad_adjoint, grad_finit_diff, grad_para_shift
from .param_shift import ParamShift
from .vjp import compute_vjp, jacobian, run_circ

__all__ = [
"grad_adjoint",
"grad_finit_diff",
"grad_para_shift",
"ParamShift",
"compute_vjp",
"jacobian",
"run_circ",
]
17 changes: 13 additions & 4 deletions quafu/algorithms/gradients/gradiant.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@ def grad_para_shift(qc: QuantumCircuit, hamiltonian, backend=SVSimulator()):

for i, op in enumerate(qc.gates):
if len(op.paras) > 0:
if isinstance(op.paras[0], Parameter) or isinstance(op.paras[0], ParameterExpression):
if isinstance(op.paras[0], Parameter) or isinstance(
op.paras[0], ParameterExpression
):
if op.name not in ["RX", "RY", "RZ"]:
raise CircuitError(
"It seems the circuit can not apply parameter-shift rule to calculate gradient. You may need compile the circuit first"
"It seems the circuit can not apply parameter-shift rule to calculate gradient."
" You may need compile the circuit first"
)
op.paras[0] = op.paras[0] + np.pi / 2
res1 = sum(backend.run(qc, hamiltonian=hamiltonian)["pauli_expects"])
Expand Down Expand Up @@ -136,14 +139,20 @@ def grad_adjoint(qc, hamiltonian, psi_in=np.array([], dtype=complex)):
end = len(qc.gates)
gate_grads = [[] for _ in range(end)]
for i, op in enumerate(qc.gates):
if len(op.paras) > 0 and (isinstance(op.paras[0], Parameter) or isinstance(op.paras[0], ParameterExpression)):
if len(op.paras) > 0 and (
isinstance(op.paras[0], Parameter)
or isinstance(op.paras[0], ParameterExpression)
):
begin = i
break

for i in range(begin, end)[::-1]:
op = qc.gates[i]
phi = backend._apply_op(op.dagger(), phi)
if len(op.paras) > 0 and (isinstance(op.paras[0], Parameter) or isinstance(op.paras[0], ParameterExpression)):
if len(op.paras) > 0 and (
isinstance(op.paras[0], Parameter)
or isinstance(op.paras[0], ParameterExpression)
):
mu = np.copy(phi)
mu = backend._apply_op(grad_gate(op), mu)
gate_grads[i].append(np.real(2.0 * np.inner(lam.conj(), mu)))
Expand Down
7 changes: 3 additions & 4 deletions quafu/algorithms/gradients/vjp.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ def jacobian(


def compute_vjp(jac: np.ndarray, dy: np.ndarray):
r"""compute vector-jacobian product
r"""
Compute vector-jacobian product.
Args:
jac (np.ndarray): jac with shape (batch_size, num_outputs, num_params)
Expand Down Expand Up @@ -133,6 +134,4 @@ def compute_vjp(jac: np.ndarray, dy: np.ndarray):

# Compute vector-Jacobian product using Einstein summation convention
# the scripts simply mean 'jac-dims,dy-dims->vjp-dims'; so num_outputs is summed over
vjp = np.einsum("ijk,ij->ik", jac, dy)

return vjp
return np.einsum("ijk,ij->ik", jac, dy)
2 changes: 1 addition & 1 deletion quafu/algorithms/templates/amplitude.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def _build(self):
return gate_list


## MottonenStatePreparation related functions.
# MottonenStatePreparation related functions.
def gray_code(rank):
"""Generates the Gray code of given rank.
Expand Down
1 change: 0 additions & 1 deletion quafu/algorithms/templates/angle.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Angel Embedding in Quantum Data embedding."""
import numpy as np
import quafu.elements.element_gates as qeg
from quafu.elements import Parameter, QuantumGate

Expand Down
Loading

0 comments on commit f1cff53

Please sign in to comment.