QkCustomOp
typedef struct QkCustomOp QkCustomOpUna representación de una operación que se ha definido en C.
Este objeto de operación contiene la funcionalidad mínima que debe cumplir un objeto para poder actuar sobre un QkCircuit.
Cualquier objeto que se pueda implementar mediante QkCustomOp se distribuirá dinámicamente para añadirlo al circuito. En otras palabras, el circuito no sabe qué tipo de objeto está aceptando, pero funcionará con él siempre y cuando tenga la funcionalidad que se espera de cualquier operación.
Para ello, una operación se define mediante dos elementos: - El puntero original a la estructura de la operación. - El puntero a una tabla virtual (vtable) con las ranuras de función que definen la funcionalidad de dicha operación. Consulte qk_custom_op_vtable_new() para obtener más detalles.
Aquí tienes un ejemplo rápido de cómo queda:
// Define an operation with a single attribute.
struct foo_gate {
uint32_t num_qubits;
};
// Represents the name of the operation.
const char *FOO_NAME = "foo";
// Design the required methods for the vtable.
const char *foo_name(const void *gate) {
// Cast void to original pointer.
struct foo_gate *_self = (struct foo_gate *)gate;
// Cast once more to consume it
(void)_self;
return FOO_NAME;
}
uint32_t foo_num_qubits(const void *gate) {
struct foo_gate *self = (struct foo_gate *)gate;
// Used stored attirbute as return value.
return self->num_qubits;
}
// Use same logic below for required methods that have
// fixed values.
uint32_t foo_num_clbits(const void *gate) {
struct foo_gate *_self = (struct foo_gate *)gate;
(void)_self;
return 0;
}
// Implement all required methods.
// Build list of entries for the vtable (at least 7 required entries)
QkCustomOpVtableEntry entries[7] = {
{.slot = 0, .func = foo_name},
{.slot = 1, .func = foo_num_qubits},
{.slot = 2, .func = foo_num_clbits},
// ...
// End with sentinel value
{.slot = -1, .func = NULL},
};
// Create a vtable
QkCustomOpVtable *foo_vtable = qk_custom_op_vtable_new(entries);
// Declare a sample instance
struct foo_gate foo_3q = {
.num_qubits = 3,
};
// Create the custom operation
QkCustomOp *foo_3q_custom = qk_custom_op_new(&foo_3q, foo_vtable);
// Add to a circuit
QkCircuit *circuit = qk_circuit_new(3, 0);
uint32_t qubits[3] = {0, 1, 2};
qk_circuit_custom_operation(circuit, foo_3q_custom, qubits, NULL, NULL);Tipos de datos
QkCustomOpSlot
enum QkCustomOpSlot
Representa el índice de la tabla de funciones virtuales (Vtable) de un objeto QkCustomOp procedente del dominio C.
Cada índice con nombre hace referencia a un método obligatorio /opt imativo de los rasgos CustomOperation y Operation en Rust.
Valores:
enumerador QkCustomOpSlot_Name
enumerador QkCustomOpSlot_NumQubits
enumerador QkCustomOpSlot_NumClbits
enumerador QkCustomOpSlot_NumParams
enumerador QkCustomOpSlot_Directive
enumerador QkCustomOpSlot_IsUnitary
enumerador QkCustomOpSlot_NumCtrlQubits
enumerador QkCustomOpSlot_Label
enumerador QkCustomOpSlot_Definition
enumerador QkCustomOpSlot_Eq
enumerador QkCustomOpSlot_Clone
enumerador QkCustomOpSlot_Delete
Funciones
qk_custom_operation_new
QkCustomOp *qk_custom_operation_new(void *operation, const QkCustomOpVtable *v_table)
Crea un QkCustomOp basado en una operación cuántica definida íntegramente en C.
Aquí tienes un ejemplo rápido de cómo queda:
// Define an operation with a single attribute.
struct foo_gate {
uint32_t num_qubits;
}
// Implement all required methods
uint32_t foo_num_qubits(const void *gate) {
struct foo_gate *self = (struct foo_gate *)gate;
// Used stored attirbute as return value.
return self->num_qubits;
}
// Build list of entries for the vtable (at least 7 required entries)
QkVtableEntry entries[7] = {
{.slot = QkCustomOpSlot_NumQubits, .func = foo_num_qubits},
// ...
// End with sentinel value
{.slot = -1, .func = NULL},
};
// Create a vtable
QkCustomOpVtable *foo_vtable = qk_custom_operation_vtable_new(entries);
// Declare a sample instance
struct foo_gate foo_3q = {
.num_qubits = 3,
};
// Create the custom operation
QkCustomOp foo_3q_custom = qk_custom_operation_new(&foo_3q, foo_vtable);Seguridad
Es responsabilidad de los programadores asegurarse de que los datos incluidos en la estructura operation puedan:
- Se puede acceder a él de forma segura desde varios subprocesos simultáneamente.
- Puede ser tomado en préstamo de forma inmutable por otros subprocesos sin provocar condiciones de carrera.
- Se conservará durante toda la vida útil de la operación.
El comportamiento es indefinido si el v_table puntero proporcionado es nulo o no está alineado.
El incumplimiento de estas condiciones puede dar lugar a un comportamiento indefinido.
Parámetros
- operación : un puntero propio a la estructura de la operación.
- v_table : un puntero a una v_table correctamente construida, diseñada para funcionar con los datos a los que
operationapunta la estructura.
Devuelve
Un puntero a QkCustomOp.
qk_custom_operation_free
void qk_custom_operation_free(QkCustomOp *data)
Liberar un :c:typeQkCustomOp: propio.
Normalmente no es necesario llamar a esta función, ya que :c:func:qk_circuit_custom_operation se hace cargo del objeto.
Esta función no realiza ninguna operación si se le pasa NULL.
Seguridad
El comportamiento no está definido si no data es nulo ni un puntero de propiedad válido a un :c:typeQkCustomOp:.
Parámetros
- datos : un puntero de propiedad a los datos que se van a liberar.
qk_custom_operation_vtable_new
const QkCustomOpVtable *qk_custom_operation_vtable_new(const QkVtableEntry *slots)
Crea un QkCustomOpVtable a partir de una lista de instancias QkVtableEntry .
La tabla virtual se construye a partir de un conjunto de ranuras que contienen un índice y un puntero a una función con los tipos de argumento y de retorno correctos.
Consulta la siguiente tabla para identificar las ranuras correctas.
Ranura | Tipo de argumento(s) | Tipo de retorno | Índice | Obligatorio | Valor predeterminado |
|---|---|---|---|---|---|
name | const void * | char * | QkCustomOpSlot_Name | Sí | n/d |
num_qubits | const void * | uint32_t | QkCustomOpSlot_NumQubits | Sí | n/d |
num_clbits | const void * | uint32_t | QkCustomOpSlot_NumClbits | No | 0 |
num_params | const void * | uint32_t | QkCustomOpSlot_NumParams | No | 0 |
directive | const void * | bool | QkCustomOpSlot_Directive | No | false |
is_unitary | const void * | bool | QkCustomOpSlot_IsUnitary | No | true |
num_ctrl_qubits | const void * | uint32_t | QkCustomOpSlot_NumCtrlQubits | No | 0 |
label | const void * | char * | QkCustomOpSlot_Label | No | NULL |
definition | const void *, QkParam ** | QkCircuit * | QkCustomOpSlot_Definition | No | NULL |
eq | const void *, const void * | bool | QkCustomOpSlot_Eq | No | Comparación de punteros |
clone | const void * | void * | QkCustomOpSlot_Clone | No | alias de puntero |
delete | void * | void | QkCustomOpSlot_Delete | No | NO-OP |
Rust considerará cada función como un void puntero y la convertirá en un puntero a función con la firma correcta.
Si no se recibe un slot obligatorio, la vtable no se creará y esta función devolverá un puntero NULL . Si no se incluye una ranura opcional, la tabla virtual se creará de todos modos y sus ranuras apuntarán a las implementaciones por defecto de dichos métodos.
Si una ranura no tiene un índice válido (aparte del valor centinela), se ignorará el puntero a la función proporcionado. De este modo se garantiza que, aunque se añadan o se eliminen métodos no obligatorios del cuadro anterior, el programa siga funcionando sin problemas.
Cada lista de ranuras debe estar delimitada por un valor centinela QkVtableEntry al final. El centinela debería tener el siguiente aspecto:
QkVtableEntry sentinel = {.slot = -1, .func = NULL};Esta función dejará de leer cualquier ranura situada después de encontrar el centinela.
Seguridad
El comportamiento es indefinido si se proporciona una lista de entradas sin un valor centinela delimitador.
También puede producirse un comportamiento indefinido durante la transmutación si el puntero a función proporcionado no tiene la firma correcta.
Parámetros
- slots : un puntero a una lista de entradas delimitada por una entrada con un valor centinela.
Devuelve
Un puntero a una tabla de funciones virtual (vtable) construida o un puntero nulo si faltan entradas obligatorias.
qk_custom_operation_vtable_free
void qk_custom_operation_vtable_free(const QkCustomOpVtable *v_table)
Libera el puntero QkCustomOpVtable
Seguridad
Puede producirse un comportamiento indefinido si v_table es un o NULL un puntero no alineado e inválido a un QkCustomOpVtable.
Parámetros
- v_table – El puntero a un objeto
QkCustomOpVtable.