Notas de versão do Qiskit SDK 2.1
2.1.2
Prelúdio
O Qiskit 2.1.2 é um pequeno patch de lançamento que corrige vários erros encontrados na série 2.1.
Correções de bugs
-
No Qiskit 2.1.0, a passagem
VF2PostLayoutfoi adicionada ao estágiooptimizationdo gerenciador de passagens predefinidas quandooptimization_level=3. Entretanto, a saída do passador nunca foi aplicada ao circuito. Esta versão remove o passe do estágiooptimizationdo gerenciador de passes predefinido para economizar o custo do tempo de execução. No Qiskit 2.2.0, a passagem fará parte do estágiooptimizatione a saída será aplicada se a passagem encontrar um layout melhor. -
Foi corrigido um problema na passagem do
VF2Layoutonde, mesmo com um conjunto de sementes fixo, a saída da passagem era potencialmente não determinística; especificamente se o circuito de entrada tivesse qualquer qubits ativo que contivesse apenas operações de qubit único. Corrigido #14729 -
Foi corrigido um erro no
PassManager.run()em que a funçãocallbacknão era chamada durante a execução com vários circuitos. Agora, a chamada de retorno é acionada corretamente para cada passagem em cada circuito, inclusive na execução paralela. -
As passagens do transpilador incorporado que definem a propriedade
final_layoutagora tratarão corretamente a atualização desse campo se ele já estiver definido. Isso pode ser observado como o métodoTranspileLayout.routing_permutationagora retorna uma permutação correta depois de executar mais de uma passagem que definefinal_layout.Isso não afetou nenhuma chamada normal para
transpile()ougenerate_preset_pass_manager()usando os plug-ins internos do Qiskit; nenhum pipeline construído dessa forma tentaria definirfinal_layoutmais de uma vez. -
Foi corrigido um erro em
Target.instruction_supported()em que a verificação da ordem dos qubits da instrução era ignorada quando o método era chamado com os argumentosoperation_nameeparametersque correspondiam a uma instrução existente. -
Foi corrigido um erro de correção ao exportar circuitos com instruções de atraso usando unidades
pspara QASM3. -
Corrigido um caso de borda na exibição do
QFTcircuito. Anteriormente, quandoQFT.inverse()era chamado e, em seguida, os atributos do circuito QFT eram modificados, o nome do QFT era exibido como"IQFT_dg". Isso estava incorreto e agora mostra corretamente"IQFT". Corrigido #14758. -
Foi corrigido um vazamento de memória na coordenação do uso de
qk_circuit_get_instructioneqk_circuit_instruction_clear. -
Esclarecida a mensagem de erro para versões inválidas especificadas em
qpy.dump()para facilitar a ação. -
Foi corrigido um problema com a função
generate_preset_pass_manager()em que ela ignorava incorretamente os dados de restrições de tempo contidos em um objetoTargetfornecido quando o argumentobackendnão era definido. Corrigido #14329 -
Corrigido um erro no
SparsePauliOp.simplify()em que o método removia os termos de Pauli com base nas magnitudes de seus coeficientes antes de combinar as duplicatas. Isso causou um comportamento incorreto em dois casos extremos importantes:- Quando vários termos de Pauli idênticos tinham coeficientes pequenos que estavam individualmente abaixo do limite de simplificação, mas cuja soma excedia o limite, esses termos eram removidos incorretamente.
- Quando vários termos de Pauli idênticos tinham coeficientes acima do limite, mas somados a quase zero, eles eram mantidos incorretamente.
Consulte #14194 para obter mais detalhes.
2.1.1
Prelúdio
O Qiskit 2.1.1 é um pequeno patch de lançamento que corrige vários erros encontrados na série 2.1.
Correções de bugs
-
Foi corrigido um bug na verificação de
DAGOpNodeonde a comparação de dois objetosDAGOpNodeque contêm uma instruçãoBoxOpinstrução. Anteriormente, o atributoBoxOp.unitnão era considerado como parte da verificação de igualdade, o que poderia fazer com que dois nós desiguais fossem avaliados como iguais. -
Corrigido o aviso de descontinuidade do site Python 3.9 para que ele seja corretamente identificado como sendo causado pelo código do usuário ao importar o Qiskit. Anteriormente, ele não era identificado como sendo causado pelo código do usuário, o que significava que os filtros de aviso padrão do Python não exibiam o aviso ao usuário.
-
Foi corrigido o comportamento do argumento
max_trialsparaVF2Layoutquando definido comoNoneou um número negativo. A passagem foi documentada como limitando a pesquisa a ser baseada no tamanho do circuito ou do alvo se a opção foi definida comoNone, e como aceitando valores negativos para especificar uma pesquisa ilimitada. No entanto, em 2.1.0, esse comportamento foi alterado incorretamente, de modo queNoneexecutou uma pesquisa sem limites e o uso de um número negativo gerou um erro. Esses descuidos foram corrigidos para que o passe se comporte conforme documentado e seja consistente com as versões anteriores. -
Correção de um problema nos plug-ins de síntese de alto nível
MCXSynthesis1DirtyKG24eMCXSynthesis2DirtyKG24paraMCXGateem que os plug-ins não consideravam os qubits auxiliares limpos disponíveis como qubits auxiliares sujos disponíveis. Em particular, o plug-inMCXSynthesis2DirtyKG24não se aplicava quando um qubits auxiliar limpo e um qubits auxiliar sujo estavam disponíveis. -
Correção de uma regressão de desempenho ao criar incrementalmente
ParameterExpressioncombinando um grande número de subexpressões. Corrigido #14653
2.1.0
Prelúdio
A versão do Qiskit v2.1 apresenta vários aprimoramentos importantes em áreas-chave, incluindo a API C, os recursos do transpilador e a usabilidade do circuito quântico. Além disso, inclui muitos aprimoramentos gerais e correções de bugs. Os principais destaques incluem:
- Extensões da API C: Com base no trabalho iniciado na versão anterior, o Qiskit v2.1 adiciona suporte para a criação e a interação com circuitos quânticos por meio de funções da API C, suportando a adição de portas padrão, instruções padrão e portas unitárias. Também foi adicionado nesta versão um conjunto de funções C para criar e manipular um objeto
Targetcomo preparação para oferecer suporte a um fluxo de trabalho completo de transpilação baseado em API C na próxima versão. Além disso,QkComplex64agora é definido como um struct, servindo como uma representação independente de compilador para números complexos ao trabalhar com a API C do Qiskit. O arquivo de cabeçalho da API C também foi atualizado para que seja geralmente compatível com o uso nativo em C++.- Suporte ao conjunto de base Clifford+T: A transpilação de circuitos para um alvo com portas Clifford+T agora é suportada imediatamente. Por trás disso, se o conjunto de bases consistir apenas em portas Clifford+T, o Qiskit garante que as passagens apropriadas para lidar com essas portas sejam adicionadas aos gerenciadores de passagens predefinidos. Essa é uma etapa inicial para oferecer suporte à transpilação para back-ends tolerantes a falhas.
- Aprimoramentos para
BoxOp: Esta versão adiciona a capacidade de anexar anotações personalizadas àsBoxOpdando ainda mais suporte ao conceito de declarações de caixa do OpenQASM 3 no Qiskit. Isso também inclui a serialização de anotações nos formatos QASM e QPY. Além disso, foi adicionado o suporte ao uso de durações de alongamento em caixas.- Python 3.9 depreciação: Python 3.9 está obsoleto a partir do Qiskit v2.1 e não será mais compatível com o Qiskit v2.3.
Para obter mais detalhes sobre os itens acima e muito mais, consulte as notas de versão abaixo e visite a documentação atualizada.
Recursos da API C
-
A API do Qiskit C ( qiskit.h ) agora suporta a criação e a interação com circuitos quânticos. A API em C dos circuitos gira em torno do tipo
QkCircuitopaco que representa o circuito. O tipoQkCircuitpermite criar um circuito com qualquer elemento de circuito definido nativamente no modelo de dados Rust interno do Qiskit paraQuantumCircuit. Atualmente, isso inclui portões padrão,Measure,Delay,Reset,Barrier, eUnitaryGate. Os recursos da API C de circuitos serão expandidos em versões futuras, à medida que mais do modelo de dados do Qiskit for adicionado nativamente ao modelo de dados interno do Rust, permitindo que ele seja usado na API C.Por exemplo, você pode usar a API C para criar um estado de 1000 qubit GHZ:
#include <qiskit.h> int main() { // Create an empty circuit with 1000 qubits and 1000 clbits QkCircuit *qc = qk_circuit_new(1000, 1000); // Add a Hadamard Gate on Qubit 0 uint32_t one_qubit[1] = {0,}; qk_circuit_gate(qc, QkGate_H, one_qubit, NULL); // The NULL pointer is for the parameter array. // Since Hadamard doesn't have parameters it // is never accessed. // Add the CX Gates: uint32_t qubits[2] = {0, 0}; uint32_t num_qubits = qk_circuit_num_qubits(qc); for (int i = 1; i<num_qubits; i++) { qubits[1] = i; qk_circuit_gate(qc, QkGate_CX, qubits, NULL); } // Add the measurements: uint32_t num_clbits = qk_circuit_num_clbits(qc); for (uint32_t i = 0; i<num_clbits; i++) { qk_circuit_measure(qc, i, i); } qk_circuit_free(qc); return 0; } -
A API C do Qiskit ( qiskit.h ) agora suporta a criação de um
Targetpara representar um alvo de transpilação. Por exemplo:#include <qiskit.h> #include <math.h> int main() { // Create a Target with 3 qubits QkTarget *target = qk_target_new(3); // Create a Target Entry for a CX Gate QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX); // Define properties for CX between qubits (0, 1) with a duration of 1.93e-9 sec and error rate 3.17e-10. uint32_t qargs[2] = {0, 1}; qk_target_entry_add_property(cx_entry, qargs, 2, 1.93e-9, 3.17e-10); // Define properties for cx between qubits (1, 0) with a duration of 1.27e-9 sec and no error. uint32_t rev_qargs[2] = {1, 2}; qk_target_entry_add_property(cx_entry, rev_qargs, 2, 1.27e-9, NAN); // Add the cx entry to the target. QkExitCode result_cx = qk_target_add_instruction(target, cx_entry); // Add global ideal Y gate entry to the target QkExitCode result_y = qk_target_add_instruction(target, qk_target_entry_new(QkGate_Y)); // Create a Target entry for a Measurement with increasing duration and error as the qubit indices increase QkTargetEntry *measure = qk_target_entry_new_measure(); for (uint32_t i = 0; i< qk_target_num_qubits(target); i++) { uint32_t q[1] = {i}; qk_target_entry_add_property(measure, q, 1, 1e-6 * (i + 1), 1e-3 * (i + 1)); } QkExitCode result_measure = qk_target_add_instruction(target, measure); return 0; } -
Foi adicionado suporte para consultar as informações da versão do Qiskit a partir da API C usando as seguintes macros:
QISKIT_VERSION_MAJORnúmero da versão principal: Contém o número da versão principal.QISKIT_VERSION_MINORnúmero da versão secundária: Contém o número da versão secundária.QISKIT_VERSION_PATCHnúmero da versão do patch: contém o número da versão do patch.QISKIT_VERSIONversão do arquivo: Contém uma representação numérica das informações da versão, que pode ser usada para comparações.QISKIT_VERSION_NUMERIC(M,m,p)macro semelhante a uma função que retorna a versão " M.m.p " como um valor numérico, que pode ser usado para comparações.
Por exemplo, para verificar se a versão atual é, no mínimo, 2.1.0, você pode usar:
if (QISKIT_VERSION >= QISKIT_VERSION_NUMERIC(2, 1, 0)) { // Code for version 2.1.0 or later } -
Compatibilidade com C++ ativada para a API C. O cabeçalho gerado agora permite chamar objetos e funções diretamente do C++. Por exemplo, um observável de 100 qubits com o termo XYZ nos primeiros 3 qubits pode ser construído como
#include <iostream> #include <complex> #include <vector> #include <qiskit.h> int main() { uint32_t num_qubits = 100; // Use smart pointer with custom deleter to manage QkObs memory QkObs *obs = qk_obs_zero(num_qubits); // Construct the observable term std::complex<double> coeff_complex = 2.0; QkComplex64 coeff = qk_complex64_from_native(coeff_complex); std::vector<QkBitTerm> bit_terms = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z}; std::vector<uint32_t> indices = {0, 1, 2}; QkObsTerm term { .coeff = coeff, .len = bit_terms.size(), .bit_terms = bit_terms.data(), .indices = indices.data(), .num_qubits = num_qubits }; qk_obs_add_term(obs.get(), &term); // Print observable properties std::cout << "num_qubits: " << qk_obs_num_qubits(obs) << "\n"; std::cout << "num_terms: " << qk_obs_num_terms(obs) << "\n"; qk_obs_free(obs); return 0; }
Recursos dos circuitos
-
Adicionada uma função
random_circuit_from_graph()que gera um circuito aleatório que induz o mesmo gráfico de interação que o especificado por interaction_graph.A probabilidade de desenhar aleatoriamente uma borda do gráfico de interação como uma porta de dois qubits pode ser definida pelo usuário no atributo de peso de uma borda no gráfico de interação de entrada. Se o usuário não definir a probabilidade, cada borda será desenhada uniformemente. Ou seja, cada porta de dois qubits representada por uma borda no gráfico de interação tem a mesma probabilidade de ser adicionada ao circuito aleatório. Se apenas um subconjunto de probabilidades de borda for definido, o site
ValueErrorserá acionado.Neste exemplo,
cp_mapé uma lista de bordas com pesos arbitrários.from qiskit.circuit.random.utils import random_circuit_from_graph import rustworkx as rx pydi_graph = rx.PyDiGraph() n_q = 5 cp_map = [(0, 1, 0.18), (1, 2, 0.15), (2, 3, 0.15), (3, 4, 0.22)] pydi_graph.extend_from_weighted_edge_list(cp_map) # cp_map can be passed in directly as interaction_graph qc = random_circuit_from_graph(interaction_graph = pydi_graph, min_2q_gate_per_edge = 1, max_operands = 2, measure = True, conditional = True, reset = True, seed = 0, insert_1q_oper = True, prob_conditional = 0.21, prob_reset = 0.1) qc.draw(output='mpl')
-
Adicionado um novo método
QuantumCircuitmétodo:QuantumCircuit.has_control_flow_op()para verificar se um objetoQuantumCircuitcontém alguma operação de fluxo de controle. -
Um novo módulo
qiskit.circuit.annotatione objeto principalAnnotationforam adicionados.As anotações são uma forma de marcar instruções (atualmente apenas
BoxOp) com dados locais, personalizados pelo usuário. Esses dados devem ser consumidos por passes de transpiladores personalizados. As anotações oferecem uma maneira de anexar dados a instruções específicas, em vez de usar o objeto global-contextPropertySetdurante a compilação.Todos os objetos
Annotationos objetos têm um camponamespace. Essa chave de cadeia de caracteres é usada para pesquisas, de modo que os consumidores possam saber se eles lidam com uma anotação específica ou não. No momento, não há métodos para consultar qualquer semântica abstrata de umaAnnotationmas espera-se que esses métodos sejam expandidos no futuro.Consulte
qiskit.circuit.annotationpara uma discussão completa sobre os recursos e casos de uso. -
BoxOp(criadas porQuantumCircuit.box()) agora podem ser anotadas com instânciasAnnotationpersonalizadas. A igualdade de duas caixas depende do fato de as anotações serem iguais.Normalmente, isso é feito passando uma lista de anotações como o único argumento posicional ao usar
QuantumCircuit.box()na forma de gerenciador de contexto:from qiskit.circuit import annotation, QuantumCircuit class MyAnnotation(annotation.Annotation): namespace = "my.annotation" def __eq__(self, other): return isinstance(other, MyAnnotation) qc = QuantumCircuit() with qc.box([MyAnnotation()]): pass -
O método
UnitaryGate.control()agora usa internamenteqs_decomposition()em vez deIsometrypara a decomposição usada para definir o controleUnitaryGate. Essa alteração reduz o número deCXGateusados nodefinitionpara oControlledGateem aproximadamente 2x. -
Aprimorou a síntese de um sistema multicontrolado
U1Gatepara que ela não cresça exponencialmente com o número de controles. -
O atributo
BoxOp.durationagora pode ser umexpr.Exprcom o tipoDurationassim comoDelay.duration. Isso inclui também o suporteStretchdurante a duração de umBoxOp.
Recursos primitivos
-
Os PUBs do estimador usados como entrada para
BaseEstimatorV2.run()agora podem ser definidos usando objetosSparseObservablepara o componente observável do PUB. Isso é um acréscimo aos tipos suportados existentes de:str,Pauli,SparsePauliOp, e um mapeamento destrouPaulipara os valores defloat. No entanto, se oSparseObservablecontiver projetores, o suporte para lidar com isso dependerá da implementação primitiva. A partir desta versão, as implementações no Qiskit (StatevectorEstimatoreBackendEstimatorV2),qiskit-ibm-runtime(qiskit_ibm_runtime.EstimatorV2) e as implementações primitivas do Qiskit Aer (qiskit_aer.primitives.EstimatorV2) ainda não suportam observáveis projetivos. Os observáveis projetivos são aqueles que contêm os termos:0,1,+,-,r, oul. -
Adicione suporte à classe
DataBinpara torná-la serializável compickle. Isso permite fazer oPrimitiveJobePrimitiveResultserializável compickletambém.
OpenQASM Características
-
qasm3.dump()eqasm3.dumps()têm um novo argumentoannotation_handlers, que é usado para fornecer instâncias deannotation.OpenQASM3Serializerpara o processo de exportação OpenQASM 3, que pode serializar objetosAnnotationpersonalizados para OpenQASM 3. -
Quando o
qiskit_qasm3_import>=0.6.0estiver instalado,qasm3.load()eqasm3.loads()têm um novo argumentoannotation_handlers, que é usado para fornecer instâncias deannotation.OpenQASM3Serializerpara o processo de importação do OpenQASM 3, que pode desserializar objetosAnnotationpersonalizados de OpenQASM 3. Atualmente, esse suporte está limitado aboxstatements, pois esse é o único lugar em que o Qiskit pode representar anotações em seu modelo de dados.
Recursos do QPY
-
Adicionado um novo formato QPY versão 15 que inclui suporte para os novos objetos
Annotationcom suporte de serializadores e desserializadores externos. O formato permite que esses serializadores tenham estado, e locais seguros no formato binário são alocados para os objetos de estado personalizados e representações de anotações personalizadas. -
qpy.dump()eqpy.load()agora têm um argumento opcionalannotation_factories, que é usado para fornecer funções de construtor deannotation.QPYSerializerobjetos para lidar comAnnotationsubclasses. Eles devem ser fornecidos pelo usuário, de forma semelhante ametadata_serializer, pois, em geral, o Qiskit não pode saber sobre todos os possíveis objetos definidos externamenteAnnotationdefinidos externamente. -
Adicionada uma nova função
get_qpy_version()ao móduloqpymódulo. Essa função inspecionará um arquivo QPY e recuperará a versão do formato QPY usada na carga útil. A versão é retornada como um número inteiro, que pode ser usado para fins de registro ou depuração. veja #14201.
Recursos de informação quântica
-
Uma nova classe,
PauliLindbladMapque é uma parametrização baseada em Pauli de um subconjunto de mapas lineares de operadores multiqubit, usada em aplicativos de aprendizado de ruído. Espera-se que essa classe forme a espinha dorsal de algoritmos aprimorados de aprendizado de ruído e forneça um controle melhor e mais eficiente sobre os modelos de ruído em versões futuras do Qiskit. -
Introduziu o
QubitSparsePaulieQubitSparsePauliListque representam os mesmos conceitos quePauliePauliListrespectivamente, mas armazenam apenas termos não idênticos, de maneira análoga aSparseObservable. Essas classes destinam-se principalmente a serem usadas com o novoPauliLindbladMap.
Recursos de síntese
-
Foi adicionado um novo algoritmo de síntese para
HalfAdderGateque não requer qubits auxiliares e tem melhor contagem de CX em comparação comadder_qft_d00(): -
Adicionadas novas decomposições para
MCXGateutilização de ancillae limpa, melhorando a profundidade e a eficiência do circuito:synth_mcx_1_clean_kg24()usando 1 qubit de ancilla limpo adicionalsynth_mcx_1_dirty_kg24()usando 1 qubit de ancilla sujo adicionalsynth_mcx_2_clean_kg24()usando 2 qubits auxiliares limpos adicionaissynth_mcx_2_dirty_kg24()usando 2 qubits auxiliares sujos adicionais
Exemplo de uso:
from qiskit.synthesis.multi_controlled import synth_mcx_1_clean_kg24 n_ctrls = 10 qc = synth_mcx_1_clean_kg24(n_ctrls) qc.draw() -
A síntese de portas multicontroladas
CZGatefoi aprimorada para reduzir a contagem de portas sintetizadas; em alguns casos, é possível obter uma redução de até 99%. Isso foi feito aproveitando a síntese aprimorada em torno doMCXGatecom a sínteseCZGatetambém. -
Aprimorou o plug-in padrão para sintetizar
AnnotatedOperationobjetos. O aprimoramento é especialmente útil ao criar e transpilar circuitos controlados com portas controladas dentro deles. Por exemplo:from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import CXGate from qiskit.compiler import transpile inner = QuantumCircuit(5) inner.append(CXGate().control(3, annotated=True), [0, 1, 2, 3, 4]) controlled_inner_gate = inner.to_gate().control(2, annotated=True) qc = QuantumCircuit(15) qc.append(controlled_inner_gate, [0, 1, 2, 3, 4, 5, 6]) qct = transpile(qc, basis_gates=["cx", "u"])Esse código cria um circuito quântico
qcque contém um circuito quântico de 2 controles com um CX-gate de 3 controles dentro dele. Com o aprimoramento, o número de portas CX no circuito transpilado é reduzido de378para30. Observe que, ao especificarannotated=Trueao definir a lógica de controle, as portas controladas são criadas como operações anotadas. Isso evita a síntese ansiosa, permite que o transpilador detecte que ocontrolled_inner_gateé equivalente a um X-gate com 6 controles e escolha o melhor método de síntese disponível para X-gates multicontrolados, especialmente utilizando os qubits ancilla disponíveis. -
A função
adder_qft_d00()usada para sintetizarModularAdderGateeHalfAdderGateagora aceita um parâmetro adicionalannotated. SeTrue, a porta QFT inversa nos somadores é implementada como uma operação anotada, permitindo que o transpilador aplique otimizações adicionais. -
A Decomposição Quântica de Shannon (
qs_decomposition()) agora inclui uma otimização que reduz a contagem deCXGateno caso de a unitária de entrada ser uma unitária controlada. -
A função de síntese
synth_mcx_1_clean_b95()agora produz um circuito com menos CX-gates. -
A classe
SolovayKitaevDecompositionagora tem argumentos adicionais no inicializador, o que permite que ela seja construída diretamente a partir de um conjunto debasis_gatese umdepthpara as aproximações básicas. -
Adicionado
SolovayKitaevDecomposition.save_basic_approximations()para salvar o conjunto de aproximações básicas que a classe usa em um formato binário. Essa alteração, combinada com os novos argumentos do inicializador, permite que os usuários ignorem o uso explícito degenerate_basic_approximations()e confiar apenas emSolovayKitaevDecomposition.
Recursos do Transpiler
-
A função
generate_preset_pass_manager()agora gera um gerenciador de passagem especial quando o conjunto de base consiste apenas em portas Clifford+T. Formalmente, um conjunto de bases de Clifford+T deve conter apenas portas de Clifford, juntamente comTGate,TdgGate, ou ambos. A lista completa de portas Clifford suportadas pode ser obtida usandoget_clifford_gate_names().Por exemplo:
from qiskit.circuit import QuantumCircuit from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from qiskit.quantum_info import get_clifford_gate_names basis_gates = get_clifford_gate_names() + ["t", "tdg"] pm = generate_preset_pass_manager(basis_gates=basis_gates) qc = QuantumCircuit(1) qc.rx(0.8, 0) qct = pm.run(qc) print(qct.count_ops())Resultaria em:
OrderedDict([('h', 10210), ('t', 4508), ('tdg', 4503), ('sdg', 943), ('s', 941)])Anteriormente, o gerenciador de passagens gerado não conseguia lidar com o exemplo acima porque não conseguia decompor portas de rotação de um único qubit em portas Clifford+T
UGateem portas Clifford+T. Entretanto, o novo gerenciador de passagens usa a decomposição Solovay-Kitaev para aproximar as portas de rotação de um único qubit usando as portasH,TeTdge chama a passagemBasisTranslatortranspiler para traduzir ainda mais as portas para o conjunto de base de destino. O novo gerenciador de passagens também tem outras alterações para permitir uma tradução mais eficiente em portas Clifford+T.É importante observar que o conjunto de portas de base Clifford+T especificado deve ser universal, caso contrário, a transpilação pode não ser bem-sucedida. Embora o conjunto de portas
["h", "t", "tdg"]ou mesmo["h", "t"]seja suficiente para a universalidade, recomenda-se adicionar mais portas Clifford ao conjunto, se possível, pois, caso contrário, a tradução poderá ser menos eficiente. Por exemplo, se a porta S não for incluída, as portas S poderão ser decompostas em pares de portas T (ou seja, as portas Clifford poderão ser decompostas em portas não-Clifford, o que pode não ser o comportamento desejado).A seguir, um exemplo um pouco maior:
from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import QFTGate from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager qc = QuantumCircuit(4) qc.append(QFTGate(4), [0, 1, 2, 3]) basis_gates = ["cx", "s", "sdg", "h", "t", "tdg"] pm = generate_preset_pass_manager(basis_gates=basis_gates, optimization_level=2) qc = QuantumCircuit(4) qc.append(QFTGate(4), [0, 1, 2, 3]) qct = pm.run(qc) print(qct.count_ops())Resultaria em:
OrderedDict([('h', 96510), ('tdg', 42396), ('t', 42389), ('s', 8240), ('sdg', 8235), ('cx', 12)]) -
Adição de um novo plug-in de síntese de alto nível
HalfAdderSynthesisR25para sintetizar um arquivoHalfAdderGate. O novo plug-in é baseado emadder_ripple_r25().O
HalfAdderSynthesisDefaulttambém foi atualizado para seguir a seguinte sequência de sintetizadores de meio somador:"HalfAdder.ripple_r25"quando há qubits,"HalfAdder.ripple_c04"quando um qubit auxiliar está disponível e"HalfAdder.ripple_r25"em todos os casos restantes. -
Foram adicionados vários plug-ins de síntese de alto nível para sintetizar um
MCXGate:MCXSynthesis1CleanKG24, com base emsynth_mcx_1_clean_kg24().MCXSynthesis1DirtyKG24, com base emsynth_mcx_1_dirty_kg24().MCXSynthesis2CleanKG24, com base emsynth_mcx_2_clean_kg24().MCXSynthesis2DirtyKG24, com base emsynth_mcx_2_dirty_kg24().
A classe
MCXSynthesisDefaulttambém foi atualizada para executar a seguinte sequência de métodos de síntese do MCX até que o primeiro seja bem-sucedido: :"mcx.2_clean_kg24","mcx.1_clean_kg24","mcx.n_clean_m15","mcx.n_dirty_i15"`, ``"mcx.2_dirty_kg24","mcx.1_dirty_kg24","mcx.1_clean_b95","mcx.noaux_v24". Os métodos são ordenados de forma que os de melhor qualidade sejam aplicados primeiro. -
VF2PostLayoutfoi adicionado ao final do estágio de otimização padrão ao usar o nível de otimização 3. -
Adicionada uma nova passagem de otimização do
OptimizeCliffordTque mescla pares de T-gates consecutivos em S-gates e pares de Tdg-gates consecutivos em Sdg-gates. Essa otimização é particularmente eficaz para reduzir a contagem de T após a decomposição de Solovay-Kitaev, que produz várias portas T ou Tdg consecutivas. Por exemplo:from qiskit.circuit import QuantumCircuit from qiskit.transpiler.passes import SolovayKitaev, OptimizeCliffordT qc = QuantumCircuit(1) qc.rx(0.8, 0) # Run Solovay-Kitaev pass on qc transpiled = SolovayKitaev()(qc) print(transpiled.count_ops().get("t", 0) + transpiled.count_ops().get("tdg", 0)) # Should print 12779 # Run Clifford+T optimization optimized = OptimizeCliffordT()(transpiled) print(optimized.count_ops().get("t", 0) + optimized.count_ops().get("tdg", 0)) # Should print 9011 -
Adicionado o passe
ContextAwareDynamicalDecouplingque implementa um desacoplamento dinâmico sensível ao contexto com base em sequências Walsh-Hadamard. As sequências de atraso inseridas serão mutuamente ortogonais às sequências nos qubits vizinhos e levarão em conta os espectadores de controle/alvo das portas CX e ECR. Consulte arXiv:2403.06852 para obter mais informações.Exemplo:
from qiskit.circuit.library import QFT from qiskit.transpiler import PassManager, CouplingMap from qiskit.transpiler.passes import ALAPScheduleAnalysis, ContextAwareDynamicalDecoupling from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from qiskit.providers.fake_provider import GenericBackendV2 num_qubits = 10 circuit = QFT(num_qubits) circuit.measure_all() target = GenericBackendV2( 100, basis_gates=["id", "rz", "sx", "x", "ecr"], coupling_map=CouplingMap.from_grid(10, 10) ).target pm = generate_preset_pass_manager(optimization_level=2, target=target) dd = PassManager([ ALAPScheduleAnalysis(target=target), ContextAwareDynamicalDecoupling(target=target), ]) transpiled = pm.run(circuit) with_dd = dd.run(transpiled) with_dd.draw("mpl", idle_wires=False)
-
Foram adicionados os seguintes atributos à classe
DAGCircuitpara permitir a consulta do número de variáveis de extensão:num_stretches,num_captured_stretchesenum_declared_stretches. -
Adicionado um novo plug-in de síntese unitária
CliffordUnitarySynthesisque tenta sintetizar uma determinada porta unitária verificando se ela pode ser representada por um Clifford e, nesse caso, retorna um circuito que implementa essa unitária e consiste apenas em portas Clifford.O plug-in é chamado pela passagem
UnitarySynthesistranspiler pass quando o parâmetromethodé definido como"clifford".Além disso, o parâmetro
plugin_configdeUnitarySynthesispode ser usado para passar os seguintes parâmetros específicos do plug-in:- min_qubits: o número mínimo de qubits a ser considerado (o valor padrão é 1).
- max_qubits: o número máximo de qubits a ser considerado (o valor padrão é 3).
Por exemplo:
import math from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import UnitaryGate from qiskit.quantum_info import Operator from qiskit.transpiler.passes import UnitarySynthesis # clifford unitary over 2 qubits c2 = QuantumCircuit(2) c2.h(0) c2.rz(math.pi / 4, 1) c2.rz(math.pi / 4, 1) c2.sdg(1) uc2 = UnitaryGate(Operator(c2).data) # non-clifford unitary over 2 qubits n2 = QuantumCircuit(2) n2.h(0) n2.rz(math.pi / 4, 1) n2.sdg(1) un2 = UnitaryGate(Operator(n2).data) # quantum circuit with two unitary gates qc = QuantumCircuit(3) qc.append(uc2, [2, 1]) qc.append(un2, [0, 2]) transpiled = UnitarySynthesis(method="clifford")(qc) transpiled.draw("mpl")
A execução do código acima ressintetiza a primeira porta unitária em portas Clifford, enquanto a segunda porta permanece inalterada.
Se modificarmos o exemplo acima da seguinte forma:
config = {"min_qubits": 3} transpiled = UnitarySynthesis(method="clifford", plugin_config=config)(qc)então ambas as portas unitárias permanecem inalteradas.
Recursos de visualização
-
Introduzimos estilos personalizados para a função
dag_drawer()função. Isso permite que você passe um dicionário para o parâmetrostylecom atributos personalizados que alteram o estilo do DAG que a função retorna. Por exemplo:from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.converters import circuit_to_dag from qiskit.visualization import dag_drawer q = QuantumRegister(3, 'q') c = ClassicalRegister(3, 'c') circ = QuantumCircuit(q, c) circ.h(q[0]) circ.cx(q[0], q[1]) circ.measure(q[0], c[0]) circ.rz(0.5, q[1]).c_if(c, 2) dag = circuit_to_dag(circ) style = { "inputnodecolor": "pink", "outputnodecolor": "lightblue", "opnodecolor": "red", } dag_drawer(dag, style=style)
Notas da Atualização
-
A biblioteca
python-dateutilnão é mais uma dependência do Qiskit. Como o Qiskit v2.0 nada na biblioteca estava usando opython-dateutile o Qiskit não dependia mais da biblioteca. Esta versão o remove da lista de dependências para que não seja instalado automaticamente como um pré-requisito para usar o Qiskit. Se você estava contando com o Qiskit para instalar o dateutil como uma dependência, agora precisará garantir que está instalando-o manualmente (o que é uma prática recomendada para dependências diretas). -
sympynão é mais um requisito para a instalação do Qiskit. Após a migração para um mecanismo simbólico baseado em Rust para a classeParameterExpressionos usos do SymPy estão isolados em alguns utilitários de visualização, na passagem doTemplateOptimizationpassagem do transpilador,ParameterExpression.sympify()(que é explicitamente para a interoperabilidade do SymPy ) eSparsePauliOp.simplify()se estiver usando coeficientes parametrizados. Essa funcionalidade não é a mais usada, portanto, o SymPy agora é tratado como uma dependência opcional e essas funções gerarão umaMissingOptionalLibraryErrorse forem usadas e o SymPy não estiver instalado. -
A dependência de
symengineque era usada para criar objetosParameterExpressionfoi removida. Ele foi substituído por um mecanismo simbólico interno e não é mais necessário para a funcionalidade principal do Qiskit. A única exceção é que o symengine foi incorporado aos formatos QPY 10, 11 e 12, portanto, ainda é necessário se você estiver desserializando esses formatos. A dependência do symengine para oqpy.load()foi explicitamente tornada opcional em 2.0.0, mas se você dependia anteriormente da instalação do symengine por padrão para essa funcionalidade, agora precisará instalá-lo manualmente para carregar a carga útil. Se você estivesse usandoParameterExpression.sympify()para obter um objeto de expressão de mecanismo de simulação de um objetoParameterExpressionisso agora retornará uma expressãosympy. Se você precisar usar isso com o symengine, poderá aproveitar osymengine.sympifypara converter a expressãosympyem uma expressão do symengine.
Notas sobre atualização de circuitos
-
O atributo
definitiondo atributoHalfAdderGatefoi alterado para usar internamenteadder_ripple_r25()para gerar a definição da porta para um circuito mais eficiente sem qubits auxiliares. Se a definição antiga for desejada por algum motivo, você poderá usar diretamente a funçãoadder_qft_d00()que gerará um circuito equivalente ao quedefinitionretornaria em versões anteriores. -
O circuito retornado pela função
excitation_preserving()e pela classeExcitationPreservingagora são construídos usando um único circuitoXXPlusYYGate. Essa é uma mudança em relação às versões anteriores que usavam umRXXGateseguido de umRYYGate. Essa nova construção de circuito é equivalente, mas usa menos portas que, por definição, preservam a excitação de forma mais simples. -
Os
definitionatributos de várias portas padrão foram atualizados de acordo com os seguintes princípios:- Quando disponível, uma definição que use portas Clifford é preferível a definições que incluam portas não-Clifford.
- Quando disponível, uma definição que usa portas Clifford+T é preferível a uma que usa um
UGate. - O uso de
PhaseGateé preferível aU1Gate. - O uso de
UGateé preferível a`U2Gatee`U3Gate.
Crucialmente, o seguinte invariante ainda se mantém: ao expandir recursivamente as definições de porta, qualquer porta pode ser expressa usando apenas a base
["cx", "u"]. As definições de todas as portas padrão são todas equivalentes, portanto, nenhuma semântica por trás das portas muda, apenas a construção exata do circuito retornado para algumas portas não é mais exatamente a mesma. Essa alteração foi necessária para dar suporte à transpilação de Clifford+T. -
O Qiskit agora usa sua própria biblioteca de expressão simbólica baseada em Rust para implementar os componentes internos do
ParameterExpressioneParameter. Como esta é uma nova implementação do mecanismo de matemática simbólica principal usado para oParameterExpressionpode haver pequenas diferenças no comportamento exato de algumas funcionalidades. Ele deve sempre produzir resultados equivalentes para a API documentada. Abra uma issue se houver algum problema de correção encontrado.
Notas sobre a atualização da API C
-
A forma como os números complexos são expostos na API C do Qiskit foi alterada. Anteriormente,
QkComplex64era um typedef dependente do compilador que permitia passar tipos complexos nativos por ponteiro para a API do Qiskit (por exemplo, comodouble complex*). Embora isso fosse conveniente, essa abordagem dependia implicitamente de suposições de layout de memória que não são estritamente garantidas.O Qiskit v2.1 agora expõe o
QkComplex64 { double re; double im; }como um struct, para garantir que o layout da memória seja sempre compatível e para obter um suporte mais amplo do compilador. Por conveniência, são fornecidos os conversores dependentes do compiladorqk_complex64_from_nativeeqk_complex64_to_native, que permitem a conversão do struct para um número complexo nativo. Observe que isso só funciona em plataformas compatíveis comdouble complexou para compiladores MSVC que usam_Dcomplex.Por exemplo:
#include <qiskit.h> #include <math.h> #include <stdio.h> #include <complex.h> int main(int argc, char *argv[]) { // platform-independent constructions: QkComplex64 coeff = {5.0, 3.0}; // ... or using converter // double complex native = 5.0 + I * 3; // uses C11 standard, does not work on MSVC // QkComplex64 coeff = qk_complex64_from_native(&native); // convert from native uint32_t num_qubits = 100; QkObs *obs = qk_obs_zero(num_qubits); QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z}; uint32_t indices[3] = {0, 1, 2}; QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits}; qk_obs_add_term(obs, &term); printf("num_qubits: %u\n", qk_obs_num_qubits(obs)); printf("num_terms: %lu\n", qk_obs_num_terms(obs)); qk_obs_free(obs); return 0; }
Notas de atualização do QPY
- A versão padrão do QPY emitida por
qpy.dump()foi alterada para a versão 15 mais recente do QPY. Se você precisar gerar uma versão de formato mais antiga por algum motivo, poderá usar o argumento da palavra-chaveversionemqpy.dump()para especificar uma versão mais antiga a ser gerada.
Notas sobre a atualização da síntese
-
O formato de serialização para aproximações básicas nos algoritmos Solovay-Kitaev foi alterado de
.npypara outro formato binário, com base emserdeebincodedo Rust. Todas as rotinas que carregam aproximações básicas (comogenerate_basic_approximations(),SolovayKitaevDecomposition.load_basic_approximations()ou o inicializador deSolovayKitaev) ainda suportam o carregamento do formato legado. Qualquer novo arquivo, entretanto, será armazenado no novo formato. Se você dependia do formato antigo, faça o downgrade do Qiskit para < 2.2 e armazene os arquivos necessários. -
Os valores padrão para
SolovayKitaev(e classes relacionadas) aumentaram paradepth=12ereps=5. Isso se deve ao fato de a implementação subjacente estar agora em Rust, o que nos permite aumentar a precisão padrão e, ao mesmo tempo, ser significativamente mais rápida do que a versão anterior do Python.
Notas sobre a atualização do Transpiler
-
Os plug-ins de layout integrados para os gerenciadores de passagem atuais não conterão mais seu componente principal (por exemplo, uma instância
SabreLayoutpara o estágio "sabre" ) se não forem fornecidas restrições de acoplamento. Anteriormente, os plug-ins construíam instâncias inválidas de suas passagens de layout, supondo que a lógica separada impediria que as passagens fossem executadas e gerassem exceções.Isso não deve ter nenhum efeito significativo sobre o uso dos gerenciadores de passes predefinidos ou dos plug-ins, pois nunca foi válido chamar os passes em um estado inválido.
Notas de descontinuação
-
O suporte para a execução do Qiskit com Python 3.9 foi descontinuado e será removido na versão do Qiskit v2.3. A versão 2.3.0 é a primeira versão após Python 3.9 entrar em fim de vida útil e não ter mais suporte [1]. Isso significa que, a partir da versão 2.3.0, será necessário atualizar a versão Python que você está usando para Python 3.9 ou superior.
Circuitos obsoletos
-
A biblioteca de circuitos passou por uma refatoração na versão do Qiskit v1.3, na qual foram fornecidas alternativas para objetos do tipo
QuantumCircuitforam fornecidas que são umInstructionou uma função Python para construção. Essa refatoração permite que o compilador raciocine sobre instruções de alto nível e reduz a sobrecarga de circuitos que não exigem otimizações de alto nível.Todas as
QuantumCircuitestão agora obsoletas em favor de suas alternativas introduzidas no Qiskit v1.3. Como parte disso, a classe baseBlueprintCircuittambém está obsoleta. Todos têm um período de depreciação estendido e só serão removidos no Qiskit v3.0.A classe
BlueprintCircuitnão tem um substituto direto; em vez disso, use umQuantumCircuitdiretamente ou uma função que gere circuitos. Consulteqiskit.circuit.librarypara obter mais detalhes, mas seguem alguns circuitos comuns e suas substituições:QFT→QFTGateTwoLocal→n_local()(não se trata de um erro de digitação, essa função abrange as funçõesNLocaleTwoLocalfuncionalidade)EfficientSU2→efficient_su2()RealAmplitudes→real_amplitudes()ZZFeatureMap→zz_feature_map()QuantumVolume→quantum_volume()EvolvedOperatorAnsatz→evolved_operator_ansatz()MCXGrayCode→synth_mcx_gray_code()MCXRecursive→synth_mcx_n_dirty_i15()MCXVChain→synth_mcx_n_clean_m15()
Correções de bugs
-
Corrigido um bug na função
dag_drawer()e no métodoDAGCircuit.draw()em que a definição do argumento da palavra-chavestyle=plainnão mostrava rótulos de circuito para os nós do DAG na visualização. -
Foi corrigido um erro no método
QuantumCircuit.assign_parameters()em que os parâmetros que não eram usados no circuito e eram passados como cadeias de caracteres não eram ignorados quando o argumentostrict=Falseera definido. Consulte a edição nº 13933 para obter mais detalhes. -
Correção de casos extremos na configuração do
Makefilepara Windows, em que a variável de ambiente predefinidaOSnão correspondia à saída do comandouname -s. -
Corrigido o atributo
namedo atributoOrGateque anteriormente estava incorretamente definido como a cadeia de caracteres"and"em vez do valor esperado"or", que agora é retornado. Esse valor incorreto"and"entrava em conflito com oAndGate.namee poderia ter levado a vários problemas relacionados ao uso doOrgatee a diferenciá-lo de umAndGate. -
Foi corrigido um bug na função
qpy.load()em que podia ocorrer falha na desserialização de circuitos cujos parâmetros haviam sido reatribuídos a parâmetros com os mesmos nomes. Corrigidos os números 13720, 13720 e 13720. -
Corrigido o
GenericBackendV2para incluir agoraBoxOpcomo um tipo de instrução compatível noGenericBackendV2.targetquando o argumento da palavra-chavecontrol_flow=Trueé definido no construtor. -
Ao sintetizar uma porta
MCXGateporta com 3 controles, a função de síntesesynth_mcx_n_dirty_i15()costumava exigir um qubit auxiliar, produzindo um circuito com 5 qubits (3 de controle, 1 de destino e 1 auxiliar). Entretanto, o algoritmo de síntese real não faz uso desse qubit auxiliar. Esse comportamento agora foi corrigido: o circuito sintetizado tem mais de 4 qubits (3 de controle e 1 de destino), permitindo que a função de síntese seja aplicada em um número um pouco maior de casos. -
O
QuantumCircuit.draw()ecircuit_drawer()agora renderizará as instruçõesBoxOpinstruções em umQuantumCircuitna mesma fatia vertical se os vãos verticais não se sobrepuserem, agora são renderizadas na mesma fatia vertical, quando possível. -
Corrigido o método
QuantumCircuit.draw()e a funçãocircuit_drawer()no modo"mpl"para inserir menos espaço estranho dentro da borda esquerda ao desenharBoxOpinstâncias em umQuantumCircuit.
Outras observações
-
Adição de um novo alvo de dependência extra opcional
qpy-compat. Esse destino deve ser usado se você planeja carregar arquivosqpyarquivos usando formatos QPY mais antigos. O destino instala requisitos extras usados para carregar arquivos QPY usando versões de formato < 13. If you are only using newer QPY format versions you do no need to install this. Theqpy.dump()only generates QPY > =13 Isso só é necessário para carregar arquivos gerados com versões mais antigas (anteriores a 2.0.0 ) do Qiskit. Você pode instalar essa nova variante opcional compip install qiskit[qpy-compat]. -
Os pesos relativos dos componentes "básico" e "antecipado" do
SabreSwapeSabreLayoutforam modificados quando o rastreamento de conjunto estendido está ativo (como sempre está emSabreLayoute, por padrão, está emSabreSwap). O componente heurístico relacionado à distância entre os qubits em uma porta individual na camada frontal agora não é mais enfraquecido proporcionalmente ao número de portas na camada frontal; esse comportamento foi uma escolha histórica, mas, em circuitos grandes, tem o efeito acidental de fazer com que a camada frontal seja praticamente ignorada, o que é desastroso para a eficiência.As melhorias de roteamento resultantes devem ser mais perceptíveis para circuitos que podem ser estratificados com frequência em camadas de mais de 20 portas paralelas de dois qubits.