Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
777 lines (625 sloc) 29.1 KB
#
# Collective Knowledge (checking and installing software)
#
# See CK LICENSE.txt for licensing details
# See CK COPYRIGHT.txt for copyright details
#
# Developer: Leo Gordon, leo@dividiti.com
#
# ck benchmark program:rigetti-vqe --repetitions=3 --record --record_uoa=lg4_again3 --tags=hackathon-again,lg4,QVM,my_cobyla --env.RIGETTI_QUANTUM_DEVICE=QVM --env.VQE_MINIMIZER_METHOD=my_cobyla --env.VQE_SAMPLE_SIZE=1 --env.VQE_MAX_ITERATIONS=80 --skip_freq
cfg={} # Will be updated by CK (meta description of this module)
work={} # Will be updated by CK (temporal data)
ck=None # Will be updated by CK (initialized CK kernel)
hackathon_date = None # '20181006' # Switch to None after the hackathon
default_provider = 'ibm'
if hackathon_date:
hackathon_tag = 'hackathon-{}'.format(hackathon_date)
hackathon_remote_repo = 'ck-quantum-hackathon-{}'.format(hackathon_date)
competition_tag = 'vqe-hackathon-3'
else:
hackathon_tag = 'hackathon-dev'
hackathon_remote_repo = 'ck-quantum-challenge-vqe'
competition_tag = 'vqe-open-challenge'
import getpass
import os
import sys
from pprint import pprint
def init(i):
"""
Not to be called directly. Sets the path to the vqe_plugin.
"""
vqe_plugin_directory = os.path.join( os.path.dirname(__file__), '..', '..', 'env', 'vqe_utils' )
sys.path.append( vqe_plugin_directory ) # allow this module to import vqe_utils
return {'return':0}
def list_deployables(i):
"""
Input: {
data_uoa - name of the template soft entry
}
Output: {
dir_names - full list of deployables within the given template soft entry
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
data_uoa = i.get('data_uoa', 'template.optimizer')
load_adict = { 'action': 'load',
'module_uoa': 'soft',
'data_uoa': data_uoa,
}
r=ck.access( load_adict )
if r['return']>0: return r
template_soft_entry_path = r['path']
deployed_name_infix = r['dict']['customize'].get('deployed_name_infix', '')
python_code_common_path = os.path.join(template_soft_entry_path, 'python_code')
# gather all the subdirectories of python_code_common_path
dir_names = [dir_name for dir_name in (os.listdir( python_code_common_path )) if os.path.isdir( os.path.join( python_code_common_path, dir_name ) ) ]
if i.get('out')=='con':
ck.out("{}".format(dir_names))
return {'return': 0, 'dir_names': dir_names, 'deployed_name_infix': deployed_name_infix}
def deploy_optimizer(i):
"""
Specialization of deploy() method where type='optimizer'.
Input: {
(value) - which deployable to deploy
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
i.update({'type' : 'optimizer'})
return deploy(i)
def deploy_ansatz(i):
"""
Specialization of deploy() method where type='qiskit.ansatz'.
Input: {
(value) - which deployable to deploy
(provider) - Ansatz function is provider-dependent. Pick "ibm" or "rigetti".
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
provider = i.get('provider', default_provider)
plugin_type = {
'ibm': 'qiskit.ansatz',
'rigetti': 'pyquil.ansatz',
}[provider]
i.update({'type' : plugin_type})
return deploy(i)
def deploy(i):
"""
Input: {
type - either 'optimizer', 'qiskit.ansatz' or 'pyquil.ansatz'
(value) - which deployable to deploy
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
plugin_type = i.get('type', 'optimizer')
template_uoa = 'template.' + plugin_type
selected_value = i.get('value')
ld_output = list_deployables({ 'data_uoa': template_uoa })
dir_names = ld_output['dir_names']
deployed_name_infix = ld_output['deployed_name_infix']
plugin_subtype = plugin_type.split('.')[-1]
if not selected_value: # Acquire it interactively
select_adict = {'action': 'select_string',
'module_uoa': 'misc',
'options': dir_names,
'default': '',
'question': 'Please select the value for {}'.format(plugin_type),
}
r=ck.access( select_adict )
if r['return']>0:
return r
else:
selected_value = r['selected_value']
deployed_uoa = 'deployed.' + deployed_name_infix + selected_value
# ck.out("Creating soft:{} code-containing CK entry from a template".format(deployed_uoa))
## ck cp soft:template.optimizer soft:deployed.optimizer
#
cp_adict = { 'action': 'cp',
'module_uoa': 'soft',
'data_uoa': template_uoa,
'new_module_uoa': 'soft',
'new_data_uoa': deployed_uoa,
}
r=ck.access( cp_adict )
if r['return']>0: return r
deployed_soft_cid = '{}:{}:{}'.format(r['repo_uoa'], r['module_uoa'], r['data_uoa'])
deployed_soft_entry_path = r['path']
python_file_name = r['dict']['customize']['soft_file_universal']
python_plugin_full_path = os.path.join(deployed_soft_entry_path, 'python_code', selected_value, python_file_name)
# ck.out("Activating soft:{} CK entry as 'deployed'".format(deployed_uoa))
## ck update soft:deployed.optimizer --tags=deployed
#
update_adict = {'action': 'update',
'module_uoa': 'soft',
'data_uoa': deployed_uoa,
'tags': [ 'deployed', '.'.join([plugin_subtype, selected_value]) ],
}
r=ck.access( update_adict )
if r['return']>0: return r
# ck.out("Removing all the 'inactive' alternaitves")
for dir_name in dir_names:
if dir_name!=selected_value:
dir_path = os.path.join(deployed_soft_entry_path, 'python_code', dir_name)
ck.delete_directory( {'path': dir_path} )
# ck.out("Creating an environment entry that sets up the paths for the soft:{} CK entry".format(deployed_uoa))
## ck detect soft --tags=vqe,optimizer,lib,deployed --full_path=/Users/lg4/CK/local/soft/deployed.optimizer/python_code/optimizer.custom/custom_optimizer.py
## ck detect soft:deployed.optimizer --full_path=/Users/lg4/CK/local/soft/deployed.optimizer/python_code/optimizer.custom/custom_optimizer.py
#
detect_adict = {'action': 'detect',
'module_uoa': 'soft',
'data_uoa': deployed_uoa,
'full_path': python_plugin_full_path,
}
r=ck.access( detect_adict )
if r['return']>0: return r
deployed_env_cid = '{}:{}:{}'.format('local', 'env', r['env_data_uoa'])
if i.get('out')=='con':
ck.out( "Deployed soft entry: {}".format(deployed_soft_cid) )
ck.out( "Deployed env entry: {}".format(deployed_env_cid) )
ck.out( "Editable python source: {}".format(python_plugin_full_path))
return { 'return': 0, 'deployed_soft_cid': deployed_soft_cid, 'deployed_env_cid': deployed_env_cid, 'full_path': python_plugin_full_path }
def plugin_path(i):
"""
Input: {
type - either 'optimizer' or 'ansatz'
(tags) - extra comma-separated tags to narrow down the search
(data_uoa) - narrow the search down to just one env entry
}
Output: {
full_path - full path to the plugin python file to be edited
plugin_dir - dirname(full_path)
plugin_filename - basename(full_path)
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
plugin_type = i.get('type', 'optimizer')
data_uoa = i.get('data_uoa', '*')
tags = i.get('tags')
search_adict = {'action': 'search',
'module_uoa': 'env',
'data_uoa': data_uoa,
'tags': ','.join( ['deployed', plugin_type ] + ([tags] if tags else []) ),
}
r=ck.access( search_adict )
if r['return']>0: return r
lst_len = len(r['lst'])
if lst_len == 0:
return {'return':1, 'error':'The {} plugin with --tags="{}" does not seem to be deployed'.format(plugin_type, tags or '')}
elif lst_len > 1:
return {'return':1, 'error':'Found {} matches for {} plugin, please narrow the search down with --tags='.format(lst_len, plugin_type)}
data_uoa = r['lst'][0]['data_uoa']
load_adict = { 'action': 'load',
'module_uoa': 'env',
'data_uoa': data_uoa,
}
r=ck.access( load_adict )
if r['return']>0: return r
full_path = r['dict']['customize']['full_path']
plugin_dir = os.path.dirname( full_path )
plugin_filename = os.path.basename( full_path )
if i.get('out')=='con':
ck.out( full_path )
return {'return': 0, 'full_path': full_path, 'plugin_dir': plugin_dir, 'plugin_filename': plugin_filename}
def cleanup(i):
"""
Input: {
(type) - either 'optimizer' or 'ansatz' to only cleanup plugins of the given type
(provider) - either 'ibm' or 'rigetti' (only for ansatz plugins)
(tags) - any extra tags to narrow down the set of entries to be removed
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
tags = ['vqe', 'deployed']
if 'provider' in i:
library_name = {
'ibm': 'qiskit',
'rigetti': 'pyquil',
}[i.get('provider')]
tags.append( library_name )
plugin_type = i.get('type')
if plugin_type:
tags.append( plugin_type )
if 'tags' in i:
tags.extend( i.get('tags').split(',') )
## ck rm *:* --tags=vqe,deployed
#
rm_adict = { 'action': 'rm',
'repo_uoa': 'local',
'module_uoa': '*',
'data_uoa': '*',
'tags': ','.join( tags ),
}
r=ck.access( rm_adict )
if r['return']>0: return r
if i.get('out')=='con':
ck.out("Removed deployed soft and env entries for {} plugins".format( plugin_type if plugin_type else 'optimizer and ansatz') )
return {'return': 0}
def run(i):
"""
Input: {
(sample_size) - number of "shots" to use in each quantum program execution
(max_iterations) - a (soft) limit on the number of optimizer's iterations
(start_param_value) - set the starting value for each optimizer's parameter (a float number or the word 'random')
(repetitions) - a number of times to run the whole optimizer convergence experiment (for stats)
(provider) - 'ibm' or 'rigetti' (see default_provider)
(device) - which simulator or quantum device to run the whole experiment on (interactive by default)
(timestamp) - when the experiment was started (normally generated automatically)
(timeout) - timeout for the device
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
force_bool = i.get('f', i.get('force'))=='yes'
timestamp = i.get('timestamp')
if not timestamp: # Get current timestamp:
r=ck.get_current_date_time({})
if r['return']>0: return r
timestamp = r['iso_datetime'].split('.')[0].replace(':', '_').replace('-', '_') # cut to seconds' resolution
username = getpass.getuser()
sample_size = i.get('sample_size', 100)
max_iterations = i.get('max_iterations', 80)
repetitions = i.get('repetitions', 3)
start_param_value = i.get('start_param_value', 'random')
timeout = i.get('timeout', 300)
provider = i.get('provider', default_provider).lower()
q_device = i.get('device')
if not q_device:
device_options = {
'ibm': ['qasm_simulator', 'ibmq_qasm_simulator', 'ibmqx4', 'ibmq_16_melbourne'],
'rigetti': ['QVM', '8Q-Agave'],
}[provider]
select_adict = {'action': 'select_string',
'module_uoa': 'misc',
'options': device_options,
'default': '0',
'question': 'Please select the target device',
}
r=ck.access( select_adict )
if r['return']>0:
return r
else:
q_device = r['selected_value']
program = {
'ibm': 'qiskit-0.6-vqe',
'rigetti': 'rigetti-vqe2',
}[provider]
load_adict = { 'action': 'load',
'module_uoa': 'program',
'data_uoa': program,
}
r=ck.access( load_adict )
if r['return']>0: return r
program_entry_path = r['path']
pipeline_adict = { 'action': 'pipeline',
'prepare': 'yes',
'module_uoa': 'program',
'data_uoa': program,
'no_state_check': 'yes',
'no_compiler_description': 'yes',
'skip_calibration': 'yes',
'speed': 'no',
'energy': 'no',
'cpu_freq': '',
'gpu_freq': '',
'no_state_check': 'yes',
'skip_print_timers': 'yes',
'out': 'con',
'env':{
'VQE_SAMPLE_SIZE': sample_size,
'VQE_MAX_ITERATIONS': max_iterations,
'VQE_QUANTUM_BACKEND': q_device,
'VQE_START_PARAM_VALUE': start_param_value,
'VQE_QUANTUM_TIMEOUT': timeout,
},
}
pipeline=ck.access( pipeline_adict )
if pipeline['return']>0: return pipeline
for k in ['ready', 'fail', 'return']:
if k in pipeline:
del(pipeline[k])
ck.out('=== About to run VQE with the following parameters: ==============')
ck.out(' --device={}'.format(q_device))
ck.out(' --max_iterations={}'.format(max_iterations))
ck.out(' --start_param_value={}'.format(start_param_value))
ck.out(' --sample_size={}'.format(sample_size))
ck.out(' --repetitions={}'.format(repetitions))
ck.out(' --timeout={}'.format(timeout))
ck.out(' --timestamp={}'.format(timestamp))
ck.out('=== Selected plugins: ============================================')
## Figuring out the plugins selected via CK's interactive layer:
#
meta_attribs = {}
for plugin_type in ('hamiltonian', 'ansatz', 'optimizer'):
plugin_dependency_name = plugin_type + '-plugin'
plugin_dependency_dict = pipeline['dependencies'].get( plugin_dependency_name )
if plugin_dependency_dict:
plugin_full_path = plugin_dependency_dict['cus']['full_path']
plugin_name = os.path.basename( os.path.dirname( plugin_full_path ))
else:
plugin_name ='builtin'
meta_attribs[plugin_type] = plugin_name
ck.out(' {:>12} : {}'.format( plugin_type, plugin_name ))
record_uoa = '{}-{}-{}-hamiltonian.{}-ansatz.{}-optimizer.{}-samples.{}-start.{}-repetitions.{}'.format( \
username, timestamp, q_device, \
meta_attribs['hamiltonian'], meta_attribs['ansatz'], meta_attribs['optimizer'], \
sample_size, start_param_value, repetitions)
record_cid = 'local:experiment:{}'.format(record_uoa)
ck.out('=== Recording the results into {}\n'.format(record_cid))
if not force_bool:
rx=ck.inp({'text': '\nContinue with the above parameters [Y/n]? '})
continue_reply = rx['string'].strip().lower() or 'yes'
if continue_reply[0] != 'y':
return {'return':1, 'error':'Please set the desired parameters and run again'}
try:
stream_file_path = os.path.join( program_entry_path, 'tmp', 'vqe_stream.json')
os.remove( stream_file_path ) # the data is appended to it by each iteration, so this file has to be cleaned-up before benchmarking
except OSError:
pass
## Adding more experiment parameters to tags and meta attributes:
#
meta_attribs.update( {
'provider': provider,
'device': q_device,
'optimizer_max_iterations': str(max_iterations),
'quantum_shots': str(sample_size),
'start_param_value': str(start_param_value),
'competition': competition_tag,
} )
benchmark_adict = { 'action': 'run',
'module_uoa': 'pipeline',
'data_uoa': 'program',
'pipeline': pipeline,
'repetitions': repetitions,
'record': 'yes',
'skip_stat_analysis': 'yes',
'process_multi_keys': [ '##choices#env#*' ], # sic! If you leave it empty, you'll get too much data back.
'record_repo': 'local',
'record_uoa': record_uoa,
'tags': ','.join( ['qck', 'quantum', hackathon_tag] + [ k+'.'+meta_attribs[k] for k in meta_attribs ] ),
'meta': meta_attribs, # a "meta" dictionary within the experiment's meta.json
}
r=ck.access( benchmark_adict )
if r['return']>0: return r
ck.out('The results have been recorded into {}\n'.format(record_cid))
return r
def list_experiments(i):
"""
Input: {
(repo_uoa) - experiment repository name (defaults to '*')
(extra_tags) - extra tags to filter
(add_meta) - request to return metadata with each experiment entry
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
repo_uoa = i.get('repo_uoa', '*')
extra_tags = i.get('extra_tags')
all_tags = 'qck' + ( ',' + extra_tags if extra_tags else '' )
add_meta = i.get('add_meta')
search_adict = { 'action': 'search',
'repo_uoa': repo_uoa,
'module_uoa': 'experiment',
'data_uoa': '*',
'tags': all_tags,
'add_meta': add_meta,
}
r=ck.access( search_adict )
if r['return']>0: return r
list_of_experiments = r['lst']
repo_to_names_list = {}
for entry in list_of_experiments:
repo_uoa = entry['repo_uoa']
data_uoa = entry['data_uoa']
if not repo_uoa in repo_to_names_list:
repo_to_names_list[ repo_uoa ] = []
repo_to_names_list[ repo_uoa ] += [ data_uoa ]
if i.get('out')=='con':
for repo_uoa in repo_to_names_list:
experiments_this_repo = repo_to_names_list[ repo_uoa ]
ck.out( '{} ({}) :'.format(repo_uoa, len(experiments_this_repo) ) )
for data_uoa in experiments_this_repo:
ck.out( '\t' + data_uoa )
ck.out( '' )
return {'return':0, 'lst': list_of_experiments, 'repo_to_names_list': repo_to_names_list}
def pick_an_experiment(i):
"""
Input: {
(repo_uoa) - experiment repository name (defaults to 'local', but can be overridden by '*')
(extra_tags) - extra tags to filter
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
repo_uoa = i.get('repo_uoa', 'local')
extra_tags = i.get('extra_tags')
list_exp_adict = { 'action': 'list_experiments',
'module_uoa': 'vqe',
'repo_uoa': repo_uoa,
'extra_tags': extra_tags,
}
r=ck.access( list_exp_adict )
if r['return']>0: return r
if len(r['lst'])==0:
return {'return':1, 'error':'No experiments to choose from - please relax your filters'}
all_experiment_names = [ '{repo_uoa}:{module_uoa}:{data_uoa}'.format(**entry_dict) for entry_dict in r['lst']]
number_of_experiments = len(all_experiment_names)
select_adict = {'action': 'select_string',
'module_uoa': 'misc',
'options': all_experiment_names,
'default': str(number_of_experiments-1),
'question': 'Please select the experiment entry',
}
r=ck.access( select_adict )
if r['return']>0:
return r
else:
cid = r['selected_value']
return {'return':0, 'cid': cid}
def upload(i):
"""
Input: {
(cids[]) - CIDs of entries to upload (interactive by default)
OR
(repo_uoa) - experiment repository name (defaults to 'local', but can be overridden by '*')
(extra_tags) - extra tags to filter
(team) - team name to be added to meta_data on upload (interactive by default)
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
cids = i.get('cids')
team_name = i.get('team')
if len(cids)==0:
repo_uoa = i.get('repo_uoa', '*')
extra_tags = i.get('extra_tags')
pick_exp_adict = { 'action': 'pick_an_experiment',
'module_uoa': 'vqe',
'repo_uoa': repo_uoa,
'extra_tags': extra_tags,
}
r=ck.access( pick_exp_adict )
if r['return']>0: return r
cids = [ r['cid'] ]
if not team_name:
r = ck.inp({'text': "Your team name: "})
team_name = r['string']
update_meta_dict = { 'team': team_name } if team_name else {}
update_mmeta_dict = update_meta_dict.copy()
transfer_adict = { 'action': 'transfer',
'module_uoa': 'misc',
'cids': cids, # 'ck transfer' will perform its own cids->xcids parsing
'target_server_uoa': 'remote-ck',
'target_repo_uoa': hackathon_remote_repo,
'update_meta_dict': update_meta_dict, # extra meta data added during the transfer
'update_mmeta_dict': update_mmeta_dict, # extra meta data added during the transfer (updated location)
}
r=ck.access( transfer_adict )
if r['return']>0: return r
ck.out('Uploaded by {}'.format(team_name))
return {'return': 0}
def time_to_solution(i):
"""
Input: {
(cids[]) - CIDs of entries to compute the TTS metric for (interactive by default)
OR
(repo_uoa) - experiment repository name (defaults to 'local', but can be overridden by '*')
(extra_tags) - extra tags to filter
(delta) - delta parameter of TTS metric
(prob) - probability parameter of TTS metric
(which_fun) - 'fun_exact', 'fun_validated' or 'fun'
(which_time) - 'total_q_shots' or 'total_q_seconds'
(show_more) - more verbose if 'yes'
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
from vqe_utils import benchmark_list_of_runs
delta = float( i.get('delta', 0.15) )
prob = float( i.get('prob', 0.90) )
which_fun = i.get('which_fun', 'fun_validated')
which_time = i.get('which_time', 'total_q_shots')
show_more = i.get('show_more', '')=='yes'
cids = i.get('cids',[])
if len(cids)>0:
cid = cids[0] # FIXME: only one CID is supported at the moment
else:
repo_uoa = i.get('repo_uoa')
extra_tags = i.get('extra_tags')
pick_exp_adict = { 'action': 'pick_an_experiment',
'module_uoa': 'vqe',
'repo_uoa': repo_uoa,
'extra_tags': extra_tags,
}
r=ck.access( pick_exp_adict )
if r['return']>0: return r
cid = r['cid']
r=ck.parse_cid({'cid': cid})
if r['return']>0:
return { 'return': 1, 'error': "Cannot parse CID '{}'".format(cid) }
else:
repo_uoa = r.get('repo_uoa','')
module_uoa = r.get('module_uoa','')
data_uoa = r.get('data_uoa','')
load_point_adict = { 'action': 'load_point',
'repo_uoa': repo_uoa,
'module_uoa': module_uoa,
'data_uoa': data_uoa,
}
r=ck.access( load_point_adict )
if r['return']>0: return r
characteristics_list = r['dict']['0001']['characteristics_list']
list_of_runs = [char['run'] for char in characteristics_list]
benchmark_list_of_runs(list_of_runs, delta, prob, which_fun, which_time, show_more)
return {'return': 0}
def list_registered_emails(i):
"""
Input: {
}
Output: {
emails - a sorted list of unique registered email addresses
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
entry_address = {
'repo_uoa': 'remote-ck',
'module_uoa': 'experiment',
'data_uoa': 'quantum_coin_flip',
'remote_repo_uoa': 'ck-quantum-hackathons', # TODO: this may need changing in future
}
list_points_adict = { 'action': 'list_points' }
list_points_adict.update( entry_address )
r=ck.access( list_points_adict )
if r['return']>0: return r
point_ids = r['points']
emails = []
for point_id in point_ids:
load_point_adict = { 'action': 'load_point',
'point': point_id,
}
load_point_adict.update( entry_address )
r=ck.access( load_point_adict )
if r['return']>0: return r
email = r['dict']['0001']['characteristics_list'][0]['run']['email']
emails.append(email)
emails = sorted(set(emails))
if i.get('out')=='con':
ck.out("Unique registered emails:")
for email in emails:
ck.out('- ' + email)
return {'return': 0, 'emails': emails }
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.