|
27 | 27 | from pygsti.baseobjs.statespace import ExplicitStateSpace as _ExplicitStateSpace |
28 | 28 | from pygsti.baseobjs.statespace import QuditSpace as _QuditSpace |
29 | 29 | from pygsti.models import ExplicitOpModel as _ExplicitOpModel |
| 30 | +from pygsti.forwardsims import MatrixForwardSimulator as _MatrixForwardSimulator |
30 | 31 |
|
31 | 32 | FLOATSIZE = 8 # in bytes: TODO: a better way |
32 | 33 |
|
@@ -57,10 +58,8 @@ def find_germs(target_model, randomize=True, randomization_strength=1e-2, |
57 | 58 |
|
58 | 59 | Parameters |
59 | 60 | ---------- |
60 | | - target_model : Model or list of Model |
61 | | - The model you are aiming to implement, or a list of models that are |
62 | | - copies of the model you are trying to implement (either with or |
63 | | - without random unitary perturbations applied to the models). |
| 61 | + target_model : Model |
| 62 | + The model you are aiming to implement. |
64 | 63 |
|
65 | 64 | randomize : bool, optional |
66 | 65 | Whether or not to add random unitary perturbations to the model(s) |
@@ -188,8 +187,14 @@ def find_germs(target_model, randomize=True, randomization_strength=1e-2, |
188 | 187 | A list containing the germs making up the germ set. |
189 | 188 | """ |
190 | 189 | printer = _baseobjs.VerbosityPrinter.create_printer(verbosity, comm) |
| 190 | + |
| 191 | + if not isinstance(target_model.sim, _MatrixForwardSimulator): |
| 192 | + target_model = target_model.copy() |
| 193 | + target_model.sim = 'matrix' |
| 194 | + |
191 | 195 | modelList = _setup_model_list(target_model, randomize, |
192 | 196 | randomization_strength, num_gs_copies, seed) |
| 197 | + |
193 | 198 | gates = list(target_model.operations.keys()) |
194 | 199 | availableGermsList = [] |
195 | 200 | if candidate_germ_counts is None: candidate_germ_counts = {6: 'all upto'} |
@@ -1351,6 +1356,10 @@ def test_germ_set_finitel(model, germs_to_test, length, weights=None, |
1351 | 1356 | eigenvalues (from small to large) of the jacobian^T * jacobian |
1352 | 1357 | matrix used to determine parameter amplification. |
1353 | 1358 | """ |
| 1359 | + if not isinstance(model.sim, _MatrixForwardSimulator): |
| 1360 | + model = model.copy() |
| 1361 | + model.sim = 'matrix' |
| 1362 | + |
1354 | 1363 | # Remove any SPAM vectors from model since we only want |
1355 | 1364 | # to consider the set of *gate* parameters for amplification |
1356 | 1365 | # and this makes sure our parameter counting is correct |
@@ -3295,80 +3304,81 @@ def symmetric_low_rank_spectrum_update(update, orig_e, U, proj_U, force_rank_inc |
3295 | 3304 | #return the new eigenvalues |
3296 | 3305 | return new_evals, True |
3297 | 3306 |
|
3298 | | -#Note: This function won't work for our purposes because of the assumptions |
3299 | | -#about the rank of the update on the nullspace of the matrix we're updating, |
3300 | | -#but keeping this here commented for future reference. |
3301 | | -#Function for doing fast calculation of the updated inverse trace: |
3302 | | -#def riedel_style_inverse_trace(update, orig_e, U, proj_U, force_rank_increase=True): |
3303 | | -# """ |
3304 | | -# input: |
3305 | | -# |
3306 | | -# update : ndarray |
3307 | | -# symmetric low-rank update to perform. |
3308 | | -# This is the first half the symmetric rank decomposition s.t. |
3309 | | -# [email protected]= the full update matrix. |
3310 | | -# |
3311 | | -# orig_e : ndarray |
3312 | | -# Spectrum of the original matrix. This is a 1-D array. |
3313 | | -# |
3314 | | -# proj_U : ndarray |
3315 | | -# Projector onto the complement of the column space of the |
3316 | | -# original matrix's eigenvectors. |
3317 | | -# |
3318 | | -# output: |
3319 | | -# |
3320 | | -# trace : float |
3321 | | -# Value of the trace of the updated psuedoinverse matrix. |
3322 | | -# |
3323 | | -# updated_rank : int |
3324 | | -# total rank of the updated matrix. |
3325 | | -# |
3326 | | -# rank_increase_flag : bool |
3327 | | -# a flag that is returned to indicate is a candidate germ failed to amplify additional parameters. |
3328 | | -# This indicates things short circuited and so the scoring function should skip this germ. |
3329 | | -# """ |
3330 | | -# |
3331 | | -# #First we need to for the matrix P, whose column space |
3332 | | -# #forms an orthonormal basis for the component of update |
3333 | | -# #that is in the complement of U. |
3334 | | -# |
3335 | | -# proj_update= proj_U@update |
3336 | | -# |
3337 | | -# #Next take the RRQR decomposition of this matrix: |
3338 | | -# q_update, r_update, _ = _sla.qr(proj_update, mode='economic', pivoting=True) |
3339 | | -# |
3340 | | -# #Construct P by taking the columns of q_update corresponding to non-zero values of r_A on the diagonal. |
3341 | | -# nonzero_indices_update= _np.nonzero(_np.diag(r_update)>1e-10) #HARDCODED (threshold is hardcoded) |
3342 | | -# |
3343 | | -# #if the rank doesn't increase then we can't use the Riedel approach. |
3344 | | -# #Abort early and return a flag to indicate the rank did not increase. |
3345 | | -# if len(nonzero_indices_update[0])==0 and force_rank_increase: |
3346 | | -# return None, None, False |
3347 | | -# |
3348 | | -# P= q_update[: , nonzero_indices_update[0]] |
3349 | | -# |
3350 | | -# updated_rank= len(orig_e)+ len(nonzero_indices_update[0]) |
3351 | | -# |
3352 | | -# #Now form the matrix R_update which is given by P.T @ proj_update. |
3353 | | -# R_update= P.T@proj_update |
3354 | | -# |
3355 | | -# #R_update gets concatenated with U.T@update to form |
3356 | | -# #a block column matrixblock_column= np.concatenate([U.T@update, R_update], axis=0) |
3357 | | -# |
3358 | | -# Uta= U.T@update |
3359 | | -# |
3360 | | -# try: |
3361 | | -# RRRDinv= R_update@_np.linalg.inv(R_update.T@R_update) |
3362 | | -# except _np.linalg.LinAlgError as err: |
3363 | | -# print('Numpy thinks this matrix is singular, condition number is: ', _np.linalg.cond(R_update.T@R_update)) |
3364 | | -# print((R_update.T@R_update).shape) |
3365 | | -# raise err |
3366 | | -# pinv_orig_e_mat= _np.diag(1/orig_e) |
3367 | | -# |
3368 | | -# trace= _np.sum(1/orig_e) + _np.trace( RRRDinv@(_np.eye(Uta.shape[1]) + Uta.T@pinv_orig_e_mat@Uta)@RRRDinv.T ) |
3369 | | -# |
3370 | | -# return trace, updated_rank, True |
| 3307 | +# Note: Th function below won't work for our purposes because of the assumptions |
| 3308 | +# about the rank of the update on the nullspace of the matrix we're updating, |
| 3309 | +# but keeping this here commented for future reference. |
| 3310 | +''' |
| 3311 | +def riedel_style_inverse_trace(update, orig_e, U, proj_U, force_rank_increase=True): |
| 3312 | + """ |
| 3313 | + input: |
| 3314 | + |
| 3315 | + update : ndarray |
| 3316 | + symmetric low-rank update to perform. |
| 3317 | + This is the first half the symmetric rank decomposition s.t. |
| 3318 | + [email protected]= the full update matrix. |
| 3319 | + |
| 3320 | + orig_e : ndarray |
| 3321 | + Spectrum of the original matrix. This is a 1-D array. |
| 3322 | + |
| 3323 | + proj_U : ndarray |
| 3324 | + Projector onto the complement of the column space of the |
| 3325 | + original matrix's eigenvectors. |
| 3326 | + |
| 3327 | + output: |
| 3328 | + |
| 3329 | + trace : float |
| 3330 | + Value of the trace of the updated psuedoinverse matrix. |
| 3331 | + |
| 3332 | + updated_rank : int |
| 3333 | + total rank of the updated matrix. |
| 3334 | + |
| 3335 | + rank_increase_flag : bool |
| 3336 | + a flag that is returned to indicate is a candidate germ failed to amplify additional parameters. |
| 3337 | + This indicates things short circuited and so the scoring function should skip this germ. |
| 3338 | + """ |
3371 | 3339 | |
| 3340 | + #First we need to for the matrix P, whose column space |
| 3341 | + #forms an orthonormal basis for the component of update |
| 3342 | + #that is in the complement of U. |
| 3343 | + |
| 3344 | + proj_update= proj_U@update |
| 3345 | + |
| 3346 | + #Next take the RRQR decomposition of this matrix: |
| 3347 | + q_update, r_update, _ = _sla.qr(proj_update, mode='economic', pivoting=True) |
| 3348 | + |
| 3349 | + #Construct P by taking the columns of q_update corresponding to non-zero values of r_A on the diagonal. |
| 3350 | + nonzero_indices_update= _np.nonzero(_np.diag(r_update)>1e-10) #HARDCODED (threshold is hardcoded) |
| 3351 | + |
| 3352 | + #if the rank doesn't increase then we can't use the Riedel approach. |
| 3353 | + #Abort early and return a flag to indicate the rank did not increase. |
| 3354 | + if len(nonzero_indices_update[0])==0 and force_rank_increase: |
| 3355 | + return None, None, False |
| 3356 | + |
| 3357 | + P= q_update[: , nonzero_indices_update[0]] |
| 3358 | + |
| 3359 | + updated_rank= len(orig_e)+ len(nonzero_indices_update[0]) |
| 3360 | + |
| 3361 | + #Now form the matrix R_update which is given by P.T @ proj_update. |
| 3362 | + R_update= P.T@proj_update |
| 3363 | + |
| 3364 | + #R_update gets concatenated with U.T@update to form |
| 3365 | + #a block column matrixblock_column= np.concatenate([U.T@update, R_update], axis=0) |
| 3366 | + |
| 3367 | + Uta= U.T@update |
| 3368 | + |
| 3369 | + try: |
| 3370 | + RRRDinv= R_update@_np.linalg.inv(R_update.T@R_update) |
| 3371 | + except _np.linalg.LinAlgError as err: |
| 3372 | + print('Numpy thinks this matrix is singular, condition number is: ', _np.linalg.cond(R_update.T@R_update)) |
| 3373 | + print((R_update.T@R_update).shape) |
| 3374 | + raise err |
| 3375 | + pinv_orig_e_mat= _np.diag(1/orig_e) |
| 3376 | + |
| 3377 | + trace= _np.sum(1/orig_e) + _np.trace( RRRDinv@(_np.eye(Uta.shape[1]) + Uta.T@pinv_orig_e_mat@Uta)@RRRDinv.T ) |
| 3378 | + |
| 3379 | + return trace, updated_rank, True |
| 3380 | +''' |
| 3381 | + |
3372 | 3382 | def minamide_style_inverse_trace(update, orig_e, U, proj_U, force_rank_increase=False): |
3373 | 3383 | """ |
3374 | 3384 | This function performs a low-rank update to the components of |
|
0 commit comments