Running a simulation
When you've finished building a simulation configuration object, you can turn it into a real simulation as described in this section.
Constructing a simulation
To run the simulation, all you have to do is pass the simulation configuration
object to dqcs_sim_new()
. This function will return when all the plugins have
finished initializing as configured in the configuration object, and return a
handle to the simulation.
dqcs_sim_new()
Constructs a DQCsim simulation.
Constructs a DQCsim simulation.
dqcs_handle_t dqcs_sim_new(dqcs_handle_t scfg)
The provided handle is consumed if it is a simulation configuration, regardless of whether simulation construction succeeds.
Note that it is currently not possible to have more than one simulation handle within a single thread at the same time. This has to do with DQCsim's log system, which uses thread-local storage to determine where log messages should go. If you want to run multiple simulations in parallel, you'll have to run them from different threads.
Interacting with a simulation
After constructing the simulation, you have to explicitly tell the frontend
plugin to start executing a quantum algorithm. This is done using
dqcs_sim_start()
. This function is asynchronous: the simulation request is
only sent to the frontend when a blocking function is called. To get the
result/return value of a previously started quantum algorithm, you can use
dqcs_sim_stop()
. In fact, you have to do this for every call to
dqcs_sim_start()
, and you can't have more than one quantum algorithm running
at a time within the context of a single simulation.
dqcs_sim_start()
Starts a program on the simulated accelerator.
Starts a program on the simulated accelerator.
dqcs_return_t dqcs_sim_start(
dqcs_handle_t sim,
dqcs_handle_t data
)
This is an asynchronous call: nothing happens until yield()
,
recv()
, or wait()
is called.
The ArbData
handle is optional; if 0 is passed, an empty data object is
used. If a handle is passed, it is consumed if and only if the API call
succeeds.
dqcs_sim_wait()
Waits for the simulated accelerator to finish its current program.
Waits for the simulated accelerator to finish its current program.
dqcs_handle_t dqcs_sim_wait(dqcs_handle_t sim)
When this succeeds, the return value of the accelerator's run()
function is returned in the form of a new handle. When it fails, 0 is
returned.
Deadlocks are detected and prevented by returning an error.
While a quantum algorithm is running, you can interact with it using ArbData
message queues. You can send and receive data to and from these queues using
the following functions. The send function is asynchronous, while the receive
function will block if no messages are available.
dqcs_sim_send()
Sends a message to the simulated accelerator.
Sends a message to the simulated accelerator.
dqcs_return_t dqcs_sim_send(
dqcs_handle_t sim,
dqcs_handle_t data
)
This is an asynchronous call: nothing happens until yield()
,
recv()
, or wait()
is called.
The ArbData
handle is optional; if 0 is passed, an empty data object is
used. If a handle is passed, it is consumed if and only if the API call
succeeds.
dqcs_sim_recv()
Waits for the simulated accelerator to send a message to us.
Waits for the simulated accelerator to send a message to us.
dqcs_handle_t dqcs_sim_recv(dqcs_handle_t sim)
When this succeeds, the received data is returned in the form of a new handle. When it fails, 0 is returned.
Deadlocks are detected and prevented by returning an error.
At any time, you can force DQCsim to pass control to the frontend plugin using the following function. This is primarily useful for debugging, when you for instance want to see the results of a single sent message in the log message stream without calling a blocking function that actually does something.
dqcs_sim_yield()
Yields to the simulator.
Yields to the simulator.
dqcs_return_t dqcs_sim_yield(dqcs_handle_t sim)
The simulation runs until it blocks again. This is useful if you want an immediate response to an otherwise asynchronous call through the logging system or some communication channel outside of DQCsim's control.
This function silently returns immediately if no asynchronous data was pending or if the simulator is waiting for something that has not been sent yet.
You can also send ArbCmd
s to plugins at any time. This corresponds to calling
the host_arb
callback within a plugin. This is always synchronous; any
requests queued through dqcs_sim_start()
and dqcs_sim_send()
are processed
before the ArbCmd
, and the function waits for the ArbCmd
to finish
executing in order for it to return its result.
dqcs_sim_arb()
Sends an ArbCmd
message to one of the plugins, referenced by name.
Sends an ArbCmd
message to one of the plugins, referenced by name.
dqcs_handle_t dqcs_sim_arb(
dqcs_handle_t sim,
const char *name,
dqcs_handle_t cmd
)
ArbCmd
s are executed immediately after yielding to the simulator, so
all pending asynchronous calls are flushed and executed before the
ArbCmd
.
When this succeeds, the received data is returned in the form of a new handle. When it fails, 0 is returned.
The ArbCmd
handle is consumed if and only if the API call succeeds.
dqcs_sim_arb_idx()
Sends an ArbCmd
message to one of the plugins, referenced by index.
Sends an ArbCmd
message to one of the plugins, referenced by index.
dqcs_handle_t dqcs_sim_arb_idx(
dqcs_handle_t sim,
ssize_t index,
dqcs_handle_t cmd
)
The frontend always has index 0. 1 through N are used for the operators in front to back order (where N is the number of operators). The backend is at index N+1.
Python-style negative indices are supported. That is, -1 can be used to refer to the backend, -2 to the last operator, and so on.
ArbCmd
s are executed immediately after yielding to the simulator, so
all pending asynchronous calls are flushed and executed before the
ArbCmd
.
When this succeeds, the received data is returned in the form of a new handle. When it fails, 0 is returned.
The ArbCmd
handle is consumed if and only if the API call succeeds.
Querying plugin information
You can query the metadata associated with the plugins that make up a simulation using the following functions.
dqcs_sim_get_name()
Queries the implementation name of a plugin, referenced by instance
name.
Queries the implementation name of a plugin, referenced by instance name.
char *dqcs_sim_get_name(
dqcs_handle_t sim,
const char *name
)
On success, this returns a newly allocated string containing the
name. Free it with free()
when you're done with it to avoid memory
leaks. On failure (i.e., the handle is invalid) this returns NULL
.
dqcs_sim_get_name_idx()
Queries the implementation name of a plugin, referenced by index.
Queries the implementation name of a plugin, referenced by index.
char *dqcs_sim_get_name_idx(
dqcs_handle_t sim,
ssize_t index
)
On success, this returns a newly allocated string containing the
name. Free it with free()
when you're done with it to avoid memory
leaks. On failure (i.e., the handle is invalid) this returns NULL
.
dqcs_sim_get_author()
Queries the author of a plugin, referenced by instance name.
Queries the author of a plugin, referenced by instance name.
char *dqcs_sim_get_author(
dqcs_handle_t sim,
const char *name
)
On success, this returns a newly allocated string containing the
author. Free it with free()
when you're done with it to avoid memory
leaks. On failure (i.e., the handle is invalid) this returns NULL
.
dqcs_sim_get_author_idx()
Queries the author of a plugin, referenced by index.
Queries the author of a plugin, referenced by index.
char *dqcs_sim_get_author_idx(
dqcs_handle_t sim,
ssize_t index
)
On success, this returns a newly allocated string containing the
author. Free it with free()
when you're done with it to avoid memory
leaks. On failure (i.e., the handle is invalid) this returns NULL
.
dqcs_sim_get_version()
Queries the version of a plugin, referenced by instance name.
Queries the version of a plugin, referenced by instance name.
char *dqcs_sim_get_version(
dqcs_handle_t sim,
const char *name
)
On success, this returns a newly allocated string containing the
version. Free it with free()
when you're done with it to avoid memory
leaks. On failure (i.e., the handle is invalid) this returns NULL
.
dqcs_sim_get_version_idx()
Queries the version of a plugin, referenced by index.
Queries the version of a plugin, referenced by index.
char *dqcs_sim_get_version_idx(
dqcs_handle_t sim,
ssize_t index
)
On success, this returns a newly allocated string containing the
version. Free it with free()
when you're done with it to avoid memory
leaks. On failure (i.e., the handle is invalid) this returns NULL
.
Shutting a simulation down
When you're done with a simulation, you can just use dqcs_handle_delete()
to
shut it down. Before doing that, though, it is strongly recommended to output a
reproduction file. This file lets you reproduce the simulation exactly without
needing the host executable (or needing it to be deterministic) with just
DQCsim's command-line interface. You never know when you might need this for
debugging!
dqcs_sim_write_reproduction_file()
Writes a reproduction file for the simulation so far.
Writes a reproduction file for the simulation so far.
dqcs_return_t dqcs_sim_write_reproduction_file(
dqcs_handle_t sim,
const char *filename
)