Interacting with DQCsim
When you start a plugin with dqcs_plugin_run()
or dqcs_plugin_start()
,
DQCsim will start calling the callbacks you provided. Each of these callbacks
takes a dqcs_plugin_state_t
handle, which can be used to interact with
DQCsim and the downstream plugin(s) using the functions listed in this section.
Frontend to host communication
Within a frontend's run
callback, the following two functions can be used to
send and receive ArbData
messages to and from the host.
dqcs_plugin_send()
Sends a message to the host.
Sends a message to the host.
dqcs_return_t dqcs_plugin_send(
dqcs_plugin_state_t plugin,
dqcs_handle_t arb
)
It is only legal to call this function from within the run()
callback.
Any other source will result in an error.
The cmd
handle is consumed by this function if and only if it succeeds.
dqcs_plugin_recv()
Waits for a message from the host.
Waits for a message from the host.
dqcs_handle_t dqcs_plugin_recv(dqcs_plugin_state_t plugin)
It is only legal to call this function from within the run()
callback.
Any other source will result in an error.
When successful, this function returns a new handle to the received
ArbData
object. 0 is used to indicate that an error occurred.
The send function always returns immediately, but the receive function may
block to return control to the host if no messages were in the buffer. That
means that the latter can call into a different callback, such as host_arb
.
Upstream to downstream communication
The following functions can be used by upstream plugins (frontends and operators) to perform an operation on the downstream plugin. They correspond one-to-one with the downstream callbacks.
dqcs_plugin_allocate()
Allocate the given number of downstream qubits.
Allocate the given number of downstream qubits.
dqcs_handle_t dqcs_plugin_allocate(
dqcs_plugin_state_t plugin,
uintptr_t num_qubits,
dqcs_handle_t cq
)
Backend plugins are not allowed to call this. Doing so will result in an error.
num_qubits
specifies the number of qubits that are to be allocated.
commands
must be 0 or a valid handle to an ArbCmd
queue, containing a
list of commands that may be used to modify the behavior of the qubit
register; 0 is equivalent to zero commands. The queue is consumed by this
function, i.e. the handle becomes invalid, if and only if it succeeds.
If the function is successful, a new handle to the set of qubit references representing the newly allocated register is returned. When the function fails, 0 is returned.
dqcs_plugin_free()
Free the given downstream qubits.
Free the given downstream qubits.
dqcs_return_t dqcs_plugin_free(
dqcs_plugin_state_t plugin,
dqcs_handle_t qbset
)
Backend plugins are not allowed to call this. Doing so will result in an error.
qubits
must be a valid set of qubit references. The set is consumed by
this function, i.e. the handle becomes invalid, if and only if it succeeds.
dqcs_plugin_gate()
Tells the downstream plugin to execute a gate.
Tells the downstream plugin to execute a gate.
dqcs_return_t dqcs_plugin_gate(
dqcs_plugin_state_t plugin,
dqcs_handle_t gate
)
Backend plugins are not allowed to call this. Doing so will result in an error.
gate
must be a valid gate object. The object is consumed by this
function, i.e. the handle becomes invalid, if and only if it succeeds.
dqcs_plugin_advance()
Tells the downstream plugin to run for the specified number of cycles.
Tells the downstream plugin to run for the specified number of cycles.
dqcs_cycle_t dqcs_plugin_advance(
dqcs_plugin_state_t plugin,
dqcs_cycle_t cycles
)
Backend plugins are not allowed to call this. Doing so will result in an error.
The return value is the new cycle counter. This function uses -1 to signal an error.
dqcs_plugin_arb()
Sends an arbitrary command downstream.
Sends an arbitrary command downstream.
dqcs_handle_t dqcs_plugin_arb(
dqcs_plugin_state_t plugin,
dqcs_handle_t cmd
)
Backend plugins are not allowed to call this. Doing so will result in an error.
This function returns a new handle to an ArbData
object representing the
return value of the ArbCmd
when successful. Otherwise, it returns 0.
For performance reasons, all of the above functions except dqcs_plugin_arb()
are asynchronous. They send the associated request immediately, but it is down
to OS thread/process scheduling when the request is actually executed. This
means the following:
- The ordering of log messages sent by differing plugins depends on OS scheduling.
- Errors caused by these asynchronous functions cannot be propagated upstream.
Therefore, any error that
does
occur is necessarily fatal.
dqcs_plugin_arb()
is exempt from this since it returns a value, so ArbCmd
errors are not necessarily fatal.
Querying the state of the downstream plugin
Measurement results requested through measurement gates need to be explicitly fetched when they are needed through the following function. It always returns the result of the most recent measurement gate for a specific qubit.
dqcs_plugin_get_measurement()
Returns the latest measurement of the given downstream qubit.
Returns the latest measurement of the given downstream qubit.
dqcs_handle_t dqcs_plugin_get_measurement(
dqcs_plugin_state_t plugin,
dqcs_qubit_t qubit
)
Backend plugins are not allowed to call this. Doing so will result in an error.
If the function succeeds, it returns a new handle to a qubit measurement result object. Otherwise it returns 0.
DQCsim also records some timing information whenever a measurement is performed. This may be useful for calculating fidelity information within an algorithm running in the presence of errors.
dqcs_plugin_get_cycles_since_measure()
Returns the number of downstream cycles since the latest measurement of the
given downstream qubit.
Returns the number of downstream cycles since the latest measurement of the given downstream qubit.
dqcs_cycle_t dqcs_plugin_get_cycles_since_measure(
dqcs_plugin_state_t plugin,
dqcs_qubit_t qubit
)
Backend plugins are not allowed to call this. Doing so will result in an error.
This function uses -1 to signal an error.
dqcs_plugin_get_cycles_between_measures()
Returns the number of downstream cycles between the last two measurements
of the given downstream qubit.
Returns the number of downstream cycles between the last two measurements of the given downstream qubit.
dqcs_cycle_t dqcs_plugin_get_cycles_between_measures(
dqcs_plugin_state_t plugin,
dqcs_qubit_t qubit
)
Backend plugins are not allowed to call this. Doing so will result in an error.
This function uses -1 to signal an error.
Finally, a simulation cycle counter is maintained. This is just an accumulation
of all the dqcs_plugin_advance()
calls since the start of the simulation.
dqcs_plugin_get_cycle()
Returns the current value of the downstream cycle counter.
Returns the current value of the downstream cycle counter.
dqcs_cycle_t dqcs_plugin_get_cycle(dqcs_plugin_state_t plugin)
Backend plugins are not allowed to call this. Doing so will result in an error.
This function uses -1 to signal an error.
Random number generation
To ensure that a DQCsim simulation can be deterministically reproduced, it is strongly recommended to use the following random number generation functions.
dqcs_plugin_random_f64()
Generates a random floating point number using the simulator random seed.
Generates a random floating point number using the simulator random seed.
double dqcs_plugin_random_f64(dqcs_plugin_state_t plugin)
The generated numbers are uniformly distributed in the range [0,1>
.
This function only fails if the plugin
handle is invalid, in which case
it returns 0. Of course, 0 is also a valid (if rare) random return value.
dqcs_plugin_random_u64()
Generates a random unsigned 64-bit number using the simulator random seed.
Generates a random unsigned 64-bit number using the simulator random seed.
dqcs_handle_t dqcs_plugin_random_u64(dqcs_plugin_state_t plugin)
This function only fails if the plugin
handle is invalid, in which case
it returns 0. Of course, 0 is also a valid (if rare) random return value.
Particularly, these generators use a separate PRNG stream depending on whether
the callback they are executed from is synchronous to the upstream channel
(modify_measurement
) or the downstream channel (all other callbacks). This is
important, because the ordering of upstream callbacks with respect to
downstream callbacks is dependent on OS scheduling.
If you only use downstream callbacks, it's also fine to seed your own PRNG
using the first number returned by dqcs_plugin_random_u64()
in the init
callback. However, using a randomly seeded PRNG is strongly discouraged, since
it prevents a user from using a fixed random seed for reproduction.