QfFermionOperator
QfFermionOperator
struct QfFermionOperator
Um operador fermiónico sem spin.
Trata-se de uma estrutura de dados opaca para a API do C, cujo funcionamento interno é implementado inteiramente em Rust. O restante desta página descreve o projeto e as funções relacionadas para trabalhar com essa estrutura.
Definição
Esse operador é definido por uma combinação linear de produtos de operadores de criação e aniquilação de férmions que atuam sobre modos férmionicos sem spin. Ou seja, os termos individuais satisfazem as seguintes relações de anticomutação: [1]
onde e não distinguem as espécies de spin dos modos fermiónicos aos quais se referem.
Isso faz com que a definição do operador completo seja a seguinte:
onde e é o coeficiente (complexo) que compõe a combinação linear dos produtos. O índice pode assumir qualquer valor entre 0 e o número de modos fermiónicos sobre os quais o operador atua, menos 1.
implementação
Essa estrutura armazena os termos e coeficientes em vários vetores esparsos, de forma semelhante ao formato de linha esparsa compactada comumente utilizado para matrizes esparsas. Mais especificamente, um único operador contém 4 matrizes:
coeffs | Um vetor de coeficientes complexos composto por dois números de ponto flutuante de 64 bits. |
actions | Um vetor de valores booleanos que armazena a natureza das ações de segunda quantização. |
modes | Um vetor de inteiros de 32 bits que armazena os índices dos modos fermiónicos sobre os quais a ação foi realizada. |
boundaries | Um vetor de números inteiros que indica os limites em e actions modes. |
As entradas em actions indicam operadores de criação (aniquilação) por ( True``False ). Os modos fermiónicos indexados por modes são considerados sem spin.
É possível acessar cópias somente para leitura dessas matrizes internas por meio de suas respectivas funções:
Essa estrutura de dados permite a construção e a manipulação de operadores de maneira muito eficiente. No entanto, isso implica que um operador pode conter termos duplicados a qualquer momento. Esses problemas devem ser resolvidos manualmente por meio do uso de qf_ferm_op_simplify().
Construção
É possível construir um novo operador diretamente, especificando os vetores correspondentes descritos acima. Como alternativa, um vazio QfFermionOperator pode ser inicializado com e qf_ferm_op_zero() os termos podem ser adicionados iterativamente por meio de qf_ferm_op_add_term().
qf_ferm_op_new() | Cria um novo operador a partir das matrizes fornecidas. |
qf_ferm_op_zero() | Constrói o operador de identidade aditiva. |
qf_ferm_op_one() | Constrói o operador de identidade multiplicativa. |
qf_ferm_op_add_term() | Adiciona um termo a um já existente QfFermionOperator. |
A QfFermionOperator pode ser liberada com qf_ferm_op_free().
Aritmética
As funções a seguir permitem a realização de operações aritméticas:
qf_ferm_op_add() | Soma dois operadores. |
qf_ferm_op_mul() | Multiplica um operador por um escalar. |
qf_ferm_op_compose() | Combina dois operadores entre si. |
qf_ferm_op_adjoint() | Retorna o operador conjugado hermitiano. |
manipulação
As funções a seguir fornecem a lógica de manipulação do operador:
qf_ferm_op_ichop() | Remove termos com coeficientes de pequena magnitude. |
qf_ferm_op_simplify() | Retorna um operador equivalente, porém simplificado. |
qf_ferm_op_normal_ordered() | Retorna um operador equivalente com termos ordenados normalmente. |
qf_ferm_op_relabel_modes() | Reexibe os modos de um operador. |
Propriedades
Existem as seguintes funções para verificar determinadas propriedades de um operador.
qf_ferm_op_is_hermitian() | Retorna se um operador é hermitiano. |
qf_ferm_op_max_rank() | Retorna a classificação máxima dos termos neste operador. |
qf_ferm_op_conserves_particle_number() | Retorna se um operador conserva o número de partículas. |
[ 1 ]
https://en.wikipedia.org/wiki/Second _quantization#Operadores_de_criação_e_aniquilação_de_férmions
Membros
qf_ferm_op_new
QfFermionOperator *qf_ferm_op_new(uint64_t num_terms, uint64_t num_actions, const QkComplex64 *coeffs, const bool *actions, const uint32_t *modes, const uint32_t *boundaries)
Cria um novo operador.
Qualquer um dos argumentos do tipo ponteiro pode ser NULL se, e somente se, seu comprimento correspondente for zero.
Exemplo
1uint64_t num_terms = 3;
2uint64_t num_actions = 4;
3bool actions[4] = {true, false, true, false};
4uint32_t modes[4] = {0, 1, 2, 3};
5QkComplex64 coeffs[3] = {{1.0, 0.0}, {-1.0, 0.0}, {0.0, -1.0}};
6uint32_t boundaries[4] = {0, 0, 2, 4};
7QfFermionOperator *op = qf_ferm_op_new(num_terms, num_actions, coeffs,
8 actions, modes, boundaries);Parâmetros
- num_terms – O número de termos no operador.
- num_actions – O número de ações somadas em todos os termos.
- coeffs – Um ponteiro para uma matriz de coeficientes de termos. O comprimento dessa matriz deve ser
num_terms. - ações – Um ponteiro para uma matriz de ações sobre todos os termos. O comprimento dessa matriz deve ser
num_actions. - modos – Um ponteiro para uma matriz de modos de ação em todos os termos. O comprimento dessa matriz deve ser
num_actions. - limites – Um ponteiro para uma matriz contendo os limites entre os termos. O comprimento dessa matriz deve ser
num_terms + 1.
qf_ferm_op_free
void qf_ferm_op_free(QfFermionOperator *op)
Libera um operador existente.
Exemplo
1QfFermionOperator *op = qf_ferm_op_one();
2qf_ferm_op_free(op);Parâmetros
- op – Um ponteiro para o operador fermiónico a ser liberado.
qf_ferm_op_get_coeffs
void qf_ferm_op_get_coeffs(const QfFermionOperator *op, QkComplex64 **coeffs_out, uint64_t *coeffs_len)
Oferece acesso somente para leitura aos coeficientes do operador.
A explicação sobre a estrutura interna dos dados está aqui.
Exemplo
1uint64_t num_terms = 2;
2uint64_t num_actions = 0;
3QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
4uint32_t boundaries[3] = {0, 0, 0};
5QfFermionOperator *op =
6 qf_ferm_op_new(num_terms, num_actions, coeffs, NULL, NULL, boundaries);
7
8QkComplex64 *coeffs_out;
9uint64_t *coeffs_len;
10
11qf_ferm_op_get_coeffs(op, &coeffs_out, &coeffs_len);
12
13assert(coeffs_len == 2);Essa função retorna uma cópia dos dados internos.
Parâmetros
- op – Um ponteiro para o operador fermiónico cujos coeficientes devem ser acessados.
- coeffs_out – Um ponteiro para a matriz de valores complexos na qual os coeficientes devem ser gravados.
- coeffs_len – Um ponteiro para o inteiro no qual deve ser gravado o comprimento da matriz de saída.
qf_ferm_op_get_actions
void qf_ferm_op_get_actions(const QfFermionOperator *op, bool **actions_out, uint64_t *actions_len)
Oferece acesso somente para leitura às ações do operador.
A explicação sobre a estrutura interna dos dados está aqui.
Exemplo
1uint64_t num_terms = 2;
2uint64_t num_actions = 2;
3bool actions[2] = {true, false};
4uint32_t modes[2] = {0, 1};
5QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
6uint32_t boundaries[3] = {0, 0, 2};
7QfFermionOperator *op =
8 qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
9
10QkComplex64 *actions_out;
11uint64_t *actions_len;
12
13qf_ferm_op_get_actions(op, &actions_out, &actions_len);
14
15assert(actions_len == 2);Essa função retorna uma cópia dos dados internos.
Parâmetros
- op – Um ponteiro para o operador fermiónico cujas ações devem ser acessadas.
- actions_out – Um ponteiro para a matriz de valores booleanos na qual as ações devem ser gravadas.
- actions_len – Um ponteiro para o inteiro no qual será gravado o comprimento da matriz de saída.
qf_ferm_op_get_modes
void qf_ferm_op_get_modes(const QfFermionOperator *op, uint32_t **modes_out, uint64_t *modes_len)
Fornece acesso somente para leitura aos índices do modo sobre o qual o operador atua.
A explicação sobre a estrutura interna dos dados está aqui.
Exemplo
1uint64_t num_terms = 2;
2uint64_t num_actions = 2;
3bool actions[2] = {true, false};
4uint32_t modes[2] = {0, 1};
5QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
6uint32_t boundaries[3] = {0, 0, 2};
7QfFermionOperator *op =
8 qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
9
10QkComplex64 *modes_out;
11uint64_t *modes_len;
12
13qf_ferm_op_get_modes(op, &modes_out, &modes_len);
14
15assert(modes_len == 2);Essa função retorna uma cópia dos dados internos.
Parâmetros
- op – Um ponteiro para o operador fermiônico cujos modos devem ser acessados.
- modes_out – Um ponteiro para a matriz de valores booleanos na qual os modos devem ser gravados.
- modes_len – Um ponteiro para o número inteiro no qual será gravado o comprimento da matriz de saída.
qf_ferm_op_get_boundaries
void qf_ferm_op_get_boundaries(const QfFermionOperator *op, size_t **boundaries_out, uint64_t *boundaries_len)
Oferece acesso somente para leitura aos índices que indicam os limites entre os termos do operador.
A explicação sobre a estrutura interna dos dados está aqui.
Exemplo
1uint64_t num_terms = 2;
2uint64_t num_actions = 2;
3bool actions[2] = {true, false};
4uint32_t modes[2] = {0, 1};
5QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
6uint32_t boundaries[3] = {0, 0, 2};
7QfFermionOperator *op =
8 qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
9
10QkComplex64 *boundaries_out;
11uint64_t *boundaries_len;
12
13qf_ferm_op_get_boundaries(op, &boundaries_out, &boundaries_len);
14
15assert(boundaries_len == 3);Essa função retorna uma cópia dos dados internos.
Parâmetros
- op – Um ponteiro para o operador fermiónico cujos limites devem ser acessados.
- boundaries_out – Um ponteiro para a matriz de valores booleanos na qual os limites devem ser gravados.
- boundaries_len – Um ponteiro para o inteiro no qual será gravado o comprimento da matriz de saída.
qf_ferm_op_zero
QfFermionOperator *qf_ferm_op_zero(void)
Constrói o operador de identidade aditiva.
Adicionar o operador criado por esse método a outro não produz nenhum efeito.
Exemplo
1QfFermionOperator *zero = qf_ferm_op_zero();
2
3QfFermionOperator *op_plus_zero = qf_ferm_op_add(op, zero);
4
5assert(qf_ferm_op_equal(op, op_plus_zero));Retorna
Um ponteiro para o operador criado.
qf_ferm_op_one
QfFermionOperator *qf_ferm_op_one(void)
Constrói o operador de identidade multiplicativa.
A composição do operador construído por esse método com outro operador não produz nenhum efeito.
Exemplo
1QfFermionOperator *one = qf_ferm_op_one();
2
3QfFermionOperator *op_times_one = qf_ferm_op_compose(op, one);
4
5assert(qf_ferm_op_equal(op, op_times_one));Retorna
Um ponteiro para o operador criado.
qf_ferm_op_has_groups
bool qf_ferm_op_has_groups(const QfFermionOperator *op)
Verifica se este operador rastreia índices de grupo.
Explicação sobre os termos dos operadores de grupo: utilize a estrutura do operador.
Exemplo
1QfFCIDump *fcidump = qf_fcidump_from_file("molecule.fcidump");
2QfFermionOperator *op = qf_ferm_op_from_fcidump(fcidump);
3
4bool has_groups = qf_ferm_op_has_groups(op);
5
6assert(!has_groups);Parâmetros
- op – Um ponteiro para o operador fermiónico a ser verificado.
Retorna
Se o operador fornecido possui um atributo groups .
qf_ferm_op_num_groups
uint32_t qf_ferm_op_num_groups(const QfFermionOperator *op)
Obtém o número de grupos de um operador.
Explicação sobre os termos dos operadores de grupo: utilize a estrutura do operador.
Exemplo
1QfFCIDump *fcidump = qf_fcidump_from_file("molecule.fcidump");
2QfFermionOperator *op = qf_ferm_op_from_fcidump(fcidump);
3
4uint32_t num_groups = qf_ferm_op_num_groups(op);O número de grupos é calculado de forma preguiçosa como o maior índice de grupo encontrado mais 1.
Parâmetros
- op – Um ponteiro para o operador fermionico cujo número de grupos deve ser obtido.
Retorna
O número de índices de grupo a partir do atributo groups do operador.
qf_ferm_op_group_weights
void qf_ferm_op_group_weights(const QfFermionOperator *op, double *weights_out)
Calcula a média da magnitude absoluta do coeficiente de cada grupo.
A i-ésima entrada é a soma de abs(coeff) pelos termos do grupo i, dividida pelo número de termos desse grupo. Este é o peso de amostragem de uma fórmula de produto aleatória (por exemplo, qDRIFT ) que seleciona grupos inteiros em vez de termos individuais, e é calculado em uma única passagem pelo operador, em vez de ser obtido pela redução de e qf_ferm_op_get_coeffs() ( qf_ferm_op_get_groups() um valor por termo não agrupado cada) no lado do chamador.
Explicação sobre os termos dos operadores de grupo: utilize a estrutura do operador.
Exemplo
1uint64_t num_terms = 4;
2uint64_t num_actions = 8;
3bool actions[8] = {true, false, true, false, true, false, true, false};
4uint32_t modes[8] = {0, 1, 2, 3, 1, 0, 3, 2};
5QkComplex64 coeffs[4] = {{1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {-2.0, 0.0}};
6uint32_t boundaries[5] = {0, 2, 4, 6, 8};
7QfFermionOperator *op =
8 qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
9
10uint32_t groups_in[4] = {0, 1, 0, 1};
11qf_ferm_op_set_groups(op, groups_in, num_terms);
12
13double weights[2];
14qf_ferm_op_group_weights(op, weights);
15
16assert(weights[0] == 1.0);
17assert(weights[1] == 2.0);Um índice de grupo que nenhum termo possui pesa 0.0, o que o exclui da amostra.
Parâmetros
- op – Um ponteiro para o operador fermiónico cujos pesos de grupo devem ser calculados.
- weights_out – Um ponteiro para a matriz de valores do tipo double na qual os pesos devem ser gravados. Deve ter o tamanho de :c:func
qf_ferm_op_num_groups:.
qf_ferm_op_get_groups
void qf_ferm_op_get_groups(const QfFermionOperator *op, uint32_t **groups_out, uint64_t *groups_len)
Obtém os índices de grupo para todos os termos do operador.
Explicação sobre os termos dos operadores de grupo: utilize a estrutura do operador.
Exemplo
1QfFermionOperator *op = ...;
2uint32_t *groups_out;
3uint32_t groups_len;
4
5qf_ferm_op_get_groups(op, &groups_out, &groups_len);Parâmetros
- op – Um ponteiro para o operador fermiónico cujos índices de grupo devem ser obtidos.
- groups_out – Um ponteiro para a matriz de inteiros na qual os índices dos grupos devem ser gravados.
- groups_len – Um ponteiro para o número inteiro no qual será gravado o comprimento da matriz de saída.
qf_ferm_op_set_groups
void qf_ferm_op_set_groups(QfFermionOperator *op, const uint32_t *groups_in, uint64_t groups_len)
Define o atributo groups do operador fornecido.
Explicação sobre os termos dos operadores de grupo: utilize a estrutura do operador.
Exemplo
1QfFermionOperator *op = ...;
2
3uint32_t num_terms = 4;
4uint32_t groups_in[4] = {0, 1, 0, 1};
5qf_ferm_op_set_groups(op, groups_in, num_terms);Parâmetros
- op – Um ponteiro para o operador fermiónico cujo atributo
groupsdeve ser gravado. - groups_in – Um ponteiro para a matriz de inteiros
groupsna qual o operador deve gravar. - groups_len – O número de elementos na
groups_inmatriz.
qf_ferm_op_del_groups
void qf_ferm_op_del_groups(QfFermionOperator *op)
Exclui o atributo groups do operador fornecido.
Explicação sobre os termos dos operadores de grupo: utilize a estrutura do operador.
Exemplo
1QfFermionOperator *op = ...;
2
3qf_ferm_op_del_groups(op);Parâmetros
- op – Um ponteiro para o operador fermiónico cujo atributo
groupsdeve ser excluído.
qf_ferm_op_split_out_groups
void qf_ferm_op_split_out_groups(const QfFermionOperator *op, const uint32_t *group_indices, uint64_t num_indices, QfFermionOperator **group_ops_out)
Divide esse operador em uma lista de novos operadores com base em seu groups atributo.
Um índice duplicado em group_indices é gravado uma vez por cada ocorrência em group_ops_out. Solicitar apenas um pequeno número de grupos de um total muito maior é significativamente mais barato do que solicitar todos eles, já que os termos pertencentes a um grupo que não foi solicitado são ignorados, em vez de serem anexados em qualquer lugar.
Explicação sobre os termos dos operadores de grupo: utilize a estrutura do operador.
Exemplo
1uint64_t num_terms = 4;
2uint64_t num_actions = 8;
3bool actions[8] = {true, false, true, false, true, false, true, false};
4uint32_t modes[8] = {0, 1, 2, 3, 1, 0, 3, 2};
5QkComplex64 coeffs[4] = {{1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}};
6uint32_t boundaries[5] = {0, 2, 4, 6, 8};
7QfFermionOperator *op =
8 qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
9
10uint32_t groups_in[4] = {0, 1, 0, 1};
11qf_ferm_op_set_groups(op, groups_in, num_terms);
12
13// build every group, in index order
14QfFermionOperator *group_ops[2];
15qf_ferm_op_split_out_groups(op, NULL, 0, group_ops);
16
17// build only group 1
18uint32_t group_indices[1] = {1};
19QfFermionOperator *group_op[1];
20qf_ferm_op_split_out_groups(op, group_indices, 1, group_op);Parâmetros
- op – Um ponteiro para o operador fermiónico cujo
groupsdeve ser separado. - group_indices – Um ponteiro para a matriz de índices de grupo para os quais serão criados os operadores, na ordem de saída desejada. Talvez
NULL; nesse caso, cada grupo é construído em ordem de índice (o que equivale a passar cada índice de até0:c:func:qf_ferm_op_num_groups- 1). - num_indices – O número de índices na
group_indicesmatriz. Ignorado segroup_indicesforNULL. - group_ops_out – Um ponteiro para a matriz de :c:struct:
QfFermionOperatorna qual devem ser gravados os operadores para cada grupo solicitado. Deve ser dimensionado paranum_indicesquando nãogroup_indicesforNULL, ou para :c:func:qf_ferm_op_num_groupsquando forNULL.
qf_ferm_op_add_term
void qf_ferm_op_add_term(QfFermionOperator *op, uint64_t num_actions, const bool *actions, const uint32_t *modes, const QkComplex64 *coeff)
Adiciona um termo a um operador já existente.
Qualquer um dos argumentos do tipo ponteiro pode ser NULL se, e somente se, seu comprimento correspondente for zero.
Esta função redefine o atributo groups do operador para NULL.
Exemplo
1QfFermionOperator *one = qf_ferm_op_one();
2
3QfFermionOperator *op = qf_ferm_op_zero();
4bool actions[0] = {};
5uint32_t modes[0] = {};
6QkComplex64 coeff = {1.0, 0.0};
7
8qf_ferm_op_add_term(op, 0, actions, modes, &coeff);
9
10assert(qf_ferm_op_equal(op, one));Parâmetros
- op – Um ponteiro para o operador fermiónico a ser modificado.
- num_actions – O tamanho da matriz de ações.
- ações – Um ponteiro para uma matriz de ações. O comprimento dessa matriz deve ser
num_actions. - modos – Um ponteiro para uma matriz de modos de ação. O comprimento dessa matriz deve ser
num_actions. - coeff – Um ponteiro para o coeficiente complexo.
qf_ferm_op_add
QfFermionOperator *qf_ferm_op_add(const QfFermionOperator *left, const QfFermionOperator *right)
Soma dois operadores.
Exemplo
1QfFermionOperator *one = qf_ferm_op_one();
2QfFermionOperator *zero = qf_ferm_op_zero();
3
4QfFermionOperator *result = qf_ferm_op_add(one, zero);
5
6assert(qf_ferm_op_equal(result, one));Parâmetros
- esquerda – Um ponteiro para o operador de esquerda.
- direita – Um ponteiro para o operador de direita.
Retorna
Um ponteiro para o operador resultante.
qf_ferm_op_mul
QfFermionOperator *qf_ferm_op_mul(const QfFermionOperator *op, const QkComplex64 *scalar)
Multiplica um operador por um escalar.
Exemplo
1QfFermionOperator *one = qf_ferm_op_one();
2QkComplex64 coeff = {2.0, 0.0};
3QfFermionOperator *result = qf_ferm_op_mul(one, &coeff);
4
5QfFermionOperator *expected = qf_ferm_op_zero();
6bool actions[0] = {};
7uint32_t modes[0] = {};
8qf_ferm_op_add_term(expected, 0, actions, modes, &coeff);
9
10assert(qf_ferm_op_equal(result, expected));Parâmetros
- op – Um ponteiro para o operador.
- escalar – Um ponteiro para o escalar.
Retorna
Um ponteiro para o operador resultante.
qf_ferm_op_compose
QfFermionOperator *qf_ferm_op_compose(const QfFermionOperator *left, const QfFermionOperator *right)
Combina dois operadores entre si.
Exemplo
1QfFermionOperator *one = qf_ferm_op_one();
2QfFermionOperator *zero = qf_ferm_op_zero();
3
4QfFermionOperator *result = qf_ferm_op_compose(one, zero);
5
6assert(qf_ferm_op_equal(result, zero));Parâmetros
- esquerda – Um ponteiro para o operador de esquerda.
- direita – Um ponteiro para o operador de direita.
Retorna
Um ponteiro para o operador resultante.
qf_ferm_op_adjoint
QfFermionOperator *qf_ferm_op_adjoint(const QfFermionOperator *op)
Retorna o conjugado hermitiano (ou adjunto) de um operador.
Isso afeta os termos e coeficientes da seguinte forma:
- as ações em cada termo invertem sua ordem e alternam entre criação e aniquilação
- os coeficientes são conjugados complexos
Exemplo
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[0] = {};
3uint32_t modes[0] = {};
4QkComplex64 coeff = {0.0, 1.0};
5qf_ferm_op_add_term(op, 0, actions, modes, &coeff);
6
7QfFermionOperator *adjoint = qf_ferm_op_adjoint(op);
8
9QfFermionOperator *expected = qf_ferm_op_zero();
10QkComplex64 coeff_adj = {0.0, -1.0};
11qf_ferm_op_add_term(expected, 0, actions, modes, &coeff_adj);
12
13assert(qf_ferm_op_equal(adjoint, expected));Parâmetros
- op – Um ponteiro para o operador.
Retorna
Um ponteiro para o operador criado.
qf_ferm_op_ichop
void qf_ferm_op_ichop(QfFermionOperator *op, double atol)
Remove termos cuja magnitude do coeficiente seja inferior ao limite especificado.
Essa função trunca os coeficientes de forma avarenta! Se o operador sobre o qual a operação é realizada puder conter coeficientes distintos para termos duplicados, considere chamar qf_ferm_op_simplify() em vez disso!
Exemplo
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[0] = {};
3uint32_t modes[0] = {};
4QkComplex64 coeff = {1e-8};
5qf_ferm_op_add_term(op, 0, actions, modes, &coeff);
6
7qf_ferm_op_ichop(op, 1e-6);
8
9QfFermionOperator *expected = qf_ferm_op_zero();
10
11assert(qf_ferm_op_equal(op, expected));Parâmetros
- op – Um ponteiro para o operador.
- atol – A tolerância absoluta para o truncamento do coeficiente.
qf_ferm_op_simplify
QfFermionOperator *qf_ferm_op_simplify(const QfFermionOperator *op, double atol)
Retorna um operador equivalente, porém simplificado.
O processo de simplificação soma, primeiro, todos os coeficientes que pertencem a termos iguais e, em seguida, retém apenas aqueles cujo coeficiente total exceda a tolerância especificada (exatamente como qf_ferm_op_ichop()).
Quando um operador tiver sido manipulado aritmeticamente ou construído de forma que não garanta a unicidade dos termos, esse método deve ser chamado antes da aplicação de qualquer método que filtre coeficientes numericamente pequenos, a fim de evitar perda de informação. Veja o exemplo abaixo, que mostra como qf_ferm_op_ichop() pode truncar termos cuja soma resulta em um coeficiente de magnitude total que não deveria ser truncado:
1uint64_t num_terms = 100000;
2uint64_t num_actions = 0;
3bool actions[0] = {};
4uint32_t modes[0] = {};
5QkComplex64 coeffs[100000];
6uint32_t boundaries[100001];
7for (int i = 0; i < 100000; i++) {
8 coeffs[i].re = 1e-5;
9 coeffs[i].im = 0.0;
10 boundaries[i] = 0;
11}
12boundaries[100000] = 0;
13QfFermionOperator *op = qf_ferm_op_new(num_terms, num_actions, coeffs,
14 actions, modes, boundaries);
15
16QfFermionOperator *canon = qf_ferm_op_simplify(op, 1e-4);
17
18QfFermionOperator *one = qf_ferm_op_one();
19bool canon_is_equal = qf_ferm_op_equiv(canon, one, 1e-6);
20
21qf_ferm_op_ichop(op, 1e-4);
22
23QfFermionOperator *zero = qf_ferm_op_zero();
24bool ichop_is_equal = qf_ferm_op_equiv(op, zero, 1e-6);Parâmetros
- op – Um ponteiro para o operador fermiónico a ser simplificado.
- atol – A tolerância absoluta para o truncamento do coeficiente.
Retorna
Um operador equivalente, porém simplificado.
qf_ferm_op_normal_ordered
QfFermionOperator *qf_ferm_op_normal_ordered(const QfFermionOperator *op, const bool *sandwich)
Retorna um operador equivalente com termos ordenados normalmente.
A ordem normal de um termo de operador é definida de forma que todas as ações de criação apareçam antes de todas as ações de aniquilação. Dentro de cada grupo, os modos sobre os quais se atua são ordenados lexicograficamente. O fato de a ordem ser crescente ou decrescente depende do valor do argumento sandwich :
NULL: ambos os grupos estão ordenados em ordem lexicográfica decrescente (por exemplo,+_1 +_0 -_1 -_0)True: os índices maiores aparecem mais para o meio, ou seja, as ações de criação estão em ordem lexicográfica ascendente, enquanto as de aniquilação estão em ordem descendente (por exemplo,+_0 +_1 -_1 -_0)False: os índices menores aparecem no meio, ou seja, as ações de criação estão em ordem lexicográfica decrescente, enquanto as de aniquilação estão em ordem crescente (por exemplo,+_1 +_0 -_0 -_1)
Exemplo
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[4] = {false, true, false, true};
3uint32_t modes[4] = {1, 1, 0, 0};
4QkComplex64 coeff = {1.0, 0.0};
5qf_ferm_op_add_term(op, 4, actions, modes, &coeff);
6
7QfFermionOperator *normal_ordered = qf_ferm_op_normal_ordered(op, NULL);
8
9uint64_t num_terms = 4;
10uint64_t num_actions = 8;
11bool actions_exp[8] = {true, false, true, false, true, true, false, false};
12uint32_t modes_exp[8] = {0, 0, 1, 1, 1, 0, 1, 0};
13QkComplex64 coeffs_exp[4] = {
14 {1.0, 0.0}, {-1.0, 0.0}, {-1.0, 0.0}, {-1.0, 0.0}};
15uint32_t boundaries_exp[5] = {0, 0, 2, 4, 8};
16QfFermionOperator *expected =
17 qf_ferm_op_new(num_terms, num_actions, coeffs_exp, actions_exp,
18 modes_exp, boundaries_exp);
19
20assert(qf_ferm_op_equal(normal_ordered, expected));Quando um termo está sendo reordenado, é preciso levar em conta as relações de anticomutação, , o que implica que o número de termos pode mudar.
Parâmetros
- op – Um ponteiro para o operador.
- sandwich – Um ponteiro para um valor booleano. Esse ponteiro pode ser
NULL.
Retorna
Um ponteiro para o operador criado.
qf_ferm_op_is_hermitian
bool qf_ferm_op_is_hermitian(const QfFermionOperator *op, double atol)
Verifica se um operador é hermitiano.
Exemplo
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions1[2] = {true, false};
3uint32_t modes1[2] = {0, 1};
4QkComplex64 coeff1 = {0.0, 1.00001};
5qf_ferm_op_add_term(op, 2, actions1, modes1, &coeff1);
6bool actions2[2] = {true, false};
7uint32_t modes2[2] = {1, 0};
8QkComplex64 coeff2 = {0.0, -1};
9qf_ferm_op_add_term(op, 2, actions2, modes2, &coeff1);
10
11assert(qf_ferm_op_is_hermitian(op, 1e-4));
12assert(!qf_ferm_op_is_hermitian(op, 1e-8));Essa verificação é implementada com qf_ferm_op_equiv() base na diferença qf_ferm_op_normal_ordered() entre e op seus e qf_ferm_op_adjoint() qf_ferm_op_zero().
Parâmetros
- op – Um ponteiro para o operador fermiónico a ser verificado.
- atol – A tolerância absoluta até a qual os coeficientes são considerados iguais.
Retorna
Se o operador fornecido é hermitiano.
qf_ferm_op_max_rank
uint32_t qf_ferm_op_max_rank(const QfFermionOperator *op)
Verifica a ordem máxima de um operador.
Exemplo
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[4] = {true, false, true, false};
3uint32_t modes[4] = {0, 1, 2, 3};
4QkComplex64 coeff = {1.0, 0.0};
5qf_ferm_op_add_term(op, 4, actions, modes, &coeff);
6
7assert(qf_ferm_op_max_rank(op), 4);O comprimento do termo mais longo pode depender da forma do operador, o que significa que (por exemplo) a simplificação do operador ou a ordenação normal podem resultar em um grau máximo diferente.
Parâmetros
- op – Um ponteiro para o operador fermiónico a ser verificado.
Retorna
A classificação máxima do operador.
qf_ferm_op_conserves_particle_number
bool qf_ferm_op_conserves_particle_number(const QfFermionOperator *op)
Verifica se um operador conserva o número de partículas.
Exemplo
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions1[2] = {true, false};
3uint32_t modes1[2] = {0, 1};
4QkComplex64 coeff1 = {0.0, 1.00001};
5qf_ferm_op_add_term(op, 2, actions1, modes1, &coeff1);
6bool actions2[2] = {true, false};
7uint32_t modes2[2] = {1, 0};
8QkComplex64 coeff2 = {0.0, -1};
9qf_ferm_op_add_term(op, 2, actions2, modes2, &coeff2);
10
11assert(qf_ferm_op_is_hermitian(op, 1e-4));
12assert(!qf_ferm_op_is_hermitian(op, 1e-8));Parâmetros
- op – Um ponteiro para o operador fermiónico a ser verificado.
Retorna
Se o operador fornecido conserva o número de partículas.
qf_ferm_op_equal
bool qf_ferm_op_equal(const QfFermionOperator *left, const QfFermionOperator *right)
Compare dois operadores para verificar se são iguais.
Exemplo
1QfFermionOperator *one = qf_ferm_op_one();
2QfFermionOperator *zero = qf_ferm_op_zero();
3
4assert(qf_ferm_op_equal(one, one));
5assert(!qf_ferm_op_equal(one, zero));Parâmetros
- esquerda – Um ponteiro para o operador de esquerda.
- direita – Um ponteiro para o operador de direita.
Retorna
Se os dois operadores são iguais.
qf_ferm_op_equiv
bool qf_ferm_op_equiv(const QfFermionOperator *left, const QfFermionOperator *right, double atol)
Compare dois operadores para verificar se são equivalentes.
Equivalência, neste contexto, significa igualdade aproximada dentro dos limites da tolerância absoluta especificada. Para ser mais preciso, esse método retorna True, quando todos os valores absolutos dos coeficientes da diferença other - self estão abaixo do limite especificado atol.
Exemplo
1QfFermionOperator *zero = qf_ferm_op_zero();
2
3QfFermionOperator *op = qf_ferm_op_zero();
4bool actions[0] = {};
5uint32_t modes[0] = {};
6QkComplex64 coeff = {1e-7, 0.0};
7qf_ferm_op_add_term(op, 0, actions, modes, &coeff);
8
9assert(qf_ferm_op_equiv(op, zero, 1e-6));
10assert(!qf_ferm_op_equiv(op, zero, 1e-8));Parâmetros
- esquerda – Um ponteiro para o operador de esquerda.
- direita – Um ponteiro para o operador de direita.
- atol – A tolerância absoluta para a equivalência de coeficientes.
Retorna
Se as duas operações são equivalentes.
qf_ferm_op_len
size_t qf_ferm_op_len(const QfFermionOperator *op)
Retorna o comprimento (ou o número de termos) do operador fornecido.
Exemplo
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[4] = {true, false, true, false};
3uint32_t modes[4] = {0, 1, 2, 3};
4QkComplex64 coeff = {1.0, 0.0};
5qf_ferm_op_add_term(op, 4, actions, modes, &coeff);
6
7assert(qf_ferm_op_len(op) == 1);Parâmetros
- op – Um ponteiro para o operador fermiónico.
Retorna
O comprimento (ou número de termos) do operador.
qf_ferm_op_relabel_modes
QfExitCode qf_ferm_op_relabel_modes(QfFermionOperator *op, uint64_t num_modes, const uint32_t *permutation)
Renomeia os índices do operador fornecido.
Exemplo
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[4] = {true, false, true, false};
3uint32_t indices[4] = {0, 1, 2, 3};
4QkComplex64 coeff = {1.0, 0.0};
5qf_ferm_op_add_term(op, 4, actions, indices, &coeff);
6
7uint32_t permutation[4] = {3, 2, 1, 0};
8
9QfExitCode exit = qf_ferm_op_relabel_modes(op, 4, permutation);
10
11assert(exit == QfExitCode_Success);Parâmetros
- op – Um ponteiro para o operador fermiónico.
- num_modes – O número de índices de modo na lista de permutações fornecida.
- permutação – A lista de permutações de índices.
Retorna
Um código de saída.
QfExitCode_Successem caso de sucessoQfExitCode_DuplicateIndexErrorse forem encontrados índices duplicados na permutaçãoQfExitCode_IndexErrorpara quaisquer outros erros de índice, como índices inválidos.