mirror of https://github.com/Qiskit/qiskit.git
432 lines
14 KiB
C
432 lines
14 KiB
C
// This code is part of Qiskit.
|
|
//
|
|
// (C) Copyright IBM 2025.
|
|
//
|
|
// This code is licensed under the Apache License, Version 2.0. You may
|
|
// obtain a copy of this license in the LICENSE.txt file in the root directory
|
|
// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
|
//
|
|
// Any modifications or derivative works of this code must retain this
|
|
// copyright notice, and modified files need to carry a notice indicating
|
|
// that they have been altered from the originals.
|
|
|
|
#include "common.h"
|
|
#include <complex.h>
|
|
#include <math.h>
|
|
#include <qiskit.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
/**
|
|
* Test empty constructor for Target
|
|
*/
|
|
int test_empty_target(void) {
|
|
int result = Ok;
|
|
QkTarget *target = qk_target_new(0);
|
|
uint32_t num_qubits = qk_target_num_qubits(target);
|
|
|
|
if (num_qubits != 0) {
|
|
printf("The number of qubits %u is not 0.", num_qubits);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
double retrieved_dt = qk_target_dt(target);
|
|
if (!isnan(retrieved_dt)) {
|
|
printf("The dt value of this target %f is not %f.", retrieved_dt, NAN);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t retrieved_granularity = qk_target_granularity(target);
|
|
if (retrieved_granularity != 1) {
|
|
printf("The granularity %u is not 1.", retrieved_granularity);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t retrieved_min_length = qk_target_min_length(target);
|
|
if (retrieved_min_length != 1) {
|
|
printf("The min_length %u is not 1.", retrieved_min_length);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t pulse_alignment = qk_target_pulse_alignment(target);
|
|
if (pulse_alignment != 1) {
|
|
printf("The pulse_alignment values %u is not 1.", pulse_alignment);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t acquire_alignment = qk_target_acquire_alignment(target);
|
|
if (acquire_alignment != 1) {
|
|
printf("The acquire_alignment values %u is not 1.", acquire_alignment);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
cleanup:
|
|
qk_target_free(target);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Test constructor for Target
|
|
*/
|
|
int test_target_construct(void) {
|
|
int result = Ok;
|
|
const uint32_t num_qubits = 2;
|
|
const double dt = 10e-9;
|
|
const uint32_t granularity = 2;
|
|
const uint32_t min_length = 3;
|
|
const uint32_t p_alignment = 4;
|
|
const uint32_t a_alignment = 1;
|
|
|
|
QkTarget *target = qk_target_new(num_qubits);
|
|
|
|
qk_target_set_dt(target, dt);
|
|
qk_target_set_granularity(target, granularity);
|
|
qk_target_set_min_length(target, min_length);
|
|
qk_target_set_pulse_alignment(target, p_alignment);
|
|
qk_target_set_acquire_alignment(target, a_alignment);
|
|
|
|
uint32_t retrieved_num_qubits = qk_target_num_qubits(target);
|
|
if (retrieved_num_qubits != 2) {
|
|
printf("The number of qubits %u is not 0.", num_qubits);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
double retrieved_dt = qk_target_dt(target);
|
|
if (retrieved_dt != dt) {
|
|
printf("The dt value of this target %f is not %f.", retrieved_dt, dt);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t retrieved_granularity = qk_target_granularity(target);
|
|
if (retrieved_granularity != 2) {
|
|
printf("The granularity %u is not 2.", retrieved_granularity);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t retrieved_min_length = qk_target_min_length(target);
|
|
if (retrieved_min_length != 3) {
|
|
printf("The min_length %u is not 3.", retrieved_min_length);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t pulse_alignment = qk_target_pulse_alignment(target);
|
|
if (pulse_alignment != 4) {
|
|
printf("The pulse_alignment values %u is not 4.", pulse_alignment);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t acquire_alignment = qk_target_acquire_alignment(target);
|
|
if (acquire_alignment != 1) {
|
|
printf("The acquire_alignment values %u is not 1.", acquire_alignment);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
qk_target_free(target);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Test construction of a QkTargetEntry
|
|
*/
|
|
int test_target_entry_construction(void) {
|
|
int result = Ok;
|
|
QkTargetEntry *property_map = qk_target_entry_new(QkGate_CX);
|
|
|
|
// Test length
|
|
const size_t length = qk_target_entry_num_properties(property_map);
|
|
if (length != 0) {
|
|
printf("The initial length of the provided property map was not zero: %zu", length);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Add some qargs and properties
|
|
uint32_t qargs[2] = {0, 1};
|
|
|
|
QkExitCode result_prop = qk_target_entry_add_property(property_map, qargs, 2, 0.00018, 0.00002);
|
|
if (result_prop != QkExitCode_Success) {
|
|
printf("Unexpected error occurred when adding entry.");
|
|
}
|
|
|
|
// Test length
|
|
const size_t new_length = qk_target_entry_num_properties(property_map);
|
|
if (new_length != 1) {
|
|
printf("The initial length of the provided property map was not 1: %zu", length);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Add invalid qargs
|
|
// Add some qargs and properties
|
|
uint32_t invalid_qargs[3] = {0, 1, 2};
|
|
|
|
QkExitCode error_result =
|
|
qk_target_entry_add_property(property_map, invalid_qargs, 3, 0.00018, 0.00002);
|
|
if (error_result != QkExitCode_TargetQargMismatch) {
|
|
printf("The operation did not fail as expected for invalid qargs.");
|
|
}
|
|
|
|
cleanup:
|
|
qk_target_entry_free(property_map);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Test adding an instruction to the Target.
|
|
*/
|
|
int test_target_add_instruction(void) {
|
|
const uint32_t num_qubits = 1;
|
|
// Let's create a target with one qubit for now
|
|
QkTarget *target = qk_target_new(num_qubits);
|
|
int result = Ok;
|
|
|
|
// Add an X Gate.
|
|
// This operation is global, no property map is provided
|
|
QkExitCode result_x = qk_target_add_instruction(target, qk_target_entry_new(QkGate_X));
|
|
if (result_x != QkExitCode_Success) {
|
|
printf("Unexpected error occurred when adding a global X gate.");
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Re-add same gate, check if it fails
|
|
QkExitCode result_x_readded = qk_target_add_instruction(target, qk_target_entry_new(QkGate_X));
|
|
if (result_x_readded != QkExitCode_TargetInstAlreadyExists) {
|
|
printf("The addition of a repeated gate did not fail as expected.");
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Number of qubits of the target should not change.
|
|
uint32_t current_num_qubits = qk_target_num_qubits(target);
|
|
if (current_num_qubits != 1) {
|
|
printf("The number of qubits this target is compatible with is not 1: %u",
|
|
current_num_qubits);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
size_t current_size = qk_target_num_instructions(target);
|
|
if (current_size != 1) {
|
|
printf("The size of this target is not correct: Expected 1, got %zu", current_size);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Add a CX Gate.
|
|
// Create prop_map for the instruction
|
|
// Add property for (0, 1)
|
|
QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
|
|
uint32_t qargs[2] = {0, 1};
|
|
double inst_error = 0.0090393;
|
|
double inst_duration = 0.020039;
|
|
|
|
QkExitCode result_cx_props =
|
|
qk_target_entry_add_property(cx_entry, qargs, 2, inst_duration, inst_error);
|
|
if (result_cx_props != QkExitCode_Success) {
|
|
printf("Unexpected error occurred when adding property to a CX gate entry.");
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
QkExitCode result_cx = qk_target_add_instruction(target, cx_entry);
|
|
if (result_cx != QkExitCode_Success) {
|
|
printf("Unexpected error occurred when adding a CX gate.");
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Number of qubits of the target should change to 2.
|
|
current_num_qubits = qk_target_num_qubits(target);
|
|
if (current_num_qubits != 2) {
|
|
printf("The number of qubits this target is compatible with is not 2: %u",
|
|
current_num_qubits);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
current_size = qk_target_num_instructions(target);
|
|
if (current_size != 2) {
|
|
printf("The size of this target is not correct: Expected 2, got %zu", current_size);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Add a CRX Gate.
|
|
// Create prop_map for the instruction
|
|
// Add property for (0, 1)
|
|
double crx_params[1] = {3.14};
|
|
QkTargetEntry *crx_entry = qk_target_entry_new_fixed(QkGate_CRX, crx_params);
|
|
uint32_t crx_qargs[2] = {1, 2};
|
|
double crx_inst_error = 0.0129023;
|
|
double crx_inst_duration = 0.92939;
|
|
QkExitCode result_crx_props =
|
|
qk_target_entry_add_property(crx_entry, crx_qargs, 2, crx_inst_duration, crx_inst_error);
|
|
if (result_crx_props != QkExitCode_Success) {
|
|
printf("Unexpected error occurred when adding property to a CX gate entry.");
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
QkExitCode result_crx = qk_target_add_instruction(target, crx_entry);
|
|
if (result_crx != QkExitCode_Success) {
|
|
printf("Unexpected error occurred when adding a CX gate.");
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Number of qubits of the target should change to 3.
|
|
current_num_qubits = qk_target_num_qubits(target);
|
|
if (current_num_qubits != 3) {
|
|
printf("The number of qubits this target is compatible with is not 3: %d",
|
|
current_num_qubits);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
current_size = qk_target_num_instructions(target);
|
|
if (current_size != 3) {
|
|
printf("The size of this target is not correct: Expected 3, got %zu", current_size);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Add a measurement
|
|
QkTargetEntry *meas = qk_target_entry_new_measure();
|
|
for (uint32_t i = 0; i < 3; i++) {
|
|
uint32_t q[1] = {i};
|
|
qk_target_entry_add_property(meas, q, 1, 1e-6, 1e-4);
|
|
}
|
|
uint32_t num_meas = qk_target_entry_num_properties(meas);
|
|
if (num_meas != 3) {
|
|
printf("Expected 3 measurement entries but got: %u", num_meas);
|
|
result = EqualityError;
|
|
qk_target_entry_free(meas);
|
|
goto cleanup;
|
|
}
|
|
|
|
QkExitCode result_meas_props = qk_target_add_instruction(target, meas);
|
|
// Number of qubits of the target should remain 3.
|
|
current_num_qubits = qk_target_num_qubits(target);
|
|
if (current_num_qubits != 3) {
|
|
printf("The number of qubits this target is compatible with is not 3: %d",
|
|
current_num_qubits);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
current_size = qk_target_num_instructions(target);
|
|
if (current_size != 4) {
|
|
printf("The size of this target is not correct: Expected 4, got %zu", current_size);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Add a reset
|
|
QkTargetEntry *reset = qk_target_entry_new_reset();
|
|
for (uint32_t i = 0; i < 3; i++) {
|
|
uint32_t q[1] = {i};
|
|
qk_target_entry_add_property(reset, q, 1, 2e-6, 2e-4);
|
|
}
|
|
uint32_t num_reset = qk_target_entry_num_properties(reset);
|
|
if (num_reset != 3) {
|
|
printf("Expected 3 reset entries but got: %u", num_reset);
|
|
result = EqualityError;
|
|
qk_target_entry_free(reset);
|
|
goto cleanup;
|
|
}
|
|
|
|
qk_target_add_instruction(target, reset);
|
|
current_size = qk_target_num_instructions(target);
|
|
if (current_size != 5) {
|
|
printf("The size of this target is not correct: Expected 5, got %zu", current_size);
|
|
result = EqualityError;
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
qk_target_free(target);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Test updating an instruction property in the Target using
|
|
* `update_instruction_property`.
|
|
*/
|
|
int test_target_update_instruction(void) {
|
|
const uint32_t num_qubits = 1;
|
|
// Let's create a target with one qubit for now
|
|
QkTarget *target = qk_target_new(num_qubits);
|
|
int result = Ok;
|
|
// Add a CX Gate.
|
|
// Create prop_map for the instruction
|
|
// Add property for (0, 1)
|
|
QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
|
|
uint32_t qargs[2] = {0, 1};
|
|
double inst_error = 0.0090393;
|
|
double inst_duration = 0.020039;
|
|
qk_target_entry_add_property(cx_entry, qargs, 2, inst_duration, inst_error);
|
|
// CX Gate is not paramtric. Re-use Null
|
|
qk_target_add_instruction(target, cx_entry);
|
|
|
|
// change the intruction property of cx
|
|
double cx_new_inst_error = NAN;
|
|
double cx_new_inst_duration = 0.09457;
|
|
QkExitCode result_1 = qk_target_update_property(target, QkGate_CX, qargs, 2,
|
|
cx_new_inst_duration, cx_new_inst_error);
|
|
if (result_1 != QkExitCode_Success) {
|
|
printf("An unexpected error occured while modifying the property.");
|
|
result = RuntimeError;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Try to modify wrong instruction
|
|
QkExitCode result_2 = qk_target_update_property(target, QkGate_CH, qargs, 2,
|
|
cx_new_inst_duration, cx_new_inst_error);
|
|
if (result_2 != QkExitCode_TargetInvalidInstKey) {
|
|
printf("The function did not fail as expected when querying the wrong instruction.");
|
|
result = RuntimeError;
|
|
goto cleanup;
|
|
}
|
|
|
|
uint32_t new_qargs[2] = {1, 2};
|
|
// Try to modify wrong qargs
|
|
QkExitCode result_3 = qk_target_update_property(target, QkGate_CX, new_qargs, 2,
|
|
cx_new_inst_duration, cx_new_inst_error);
|
|
if (result_3 != QkExitCode_TargetInvalidQargsKey) {
|
|
printf("The function did not fail as expected when querying with wrong qargs.");
|
|
result = RuntimeError;
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
qk_target_free(target);
|
|
return result;
|
|
}
|
|
|
|
int test_target(void) {
|
|
int num_failed = 0;
|
|
num_failed += RUN_TEST(test_empty_target);
|
|
num_failed += RUN_TEST(test_target_construct);
|
|
num_failed += RUN_TEST(test_target_entry_construction);
|
|
num_failed += RUN_TEST(test_target_add_instruction);
|
|
num_failed += RUN_TEST(test_target_update_instruction);
|
|
|
|
fflush(stderr);
|
|
fprintf(stderr, "=== Number of failed subtests: %i\n", num_failed);
|
|
|
|
return num_failed;
|
|
}
|