Fbit
At a glance
- The
Fbitclass represents a fermionic product state in the occupation number representation of sites and . Fbitautomatically takes care of tracking the phase that occurs when permuting fermions.Fbitcan be acted upon by all fermionic operators.
Overview of Class
Fbit represents a computational basis state for spinless fermions. It contains a bit string representing the fermionic state as an integer, a complex coefficient and the number of sites of the system. A general spinless fermionic state on sites is given by linear combination of these states
where is the fermionic product state and . This ordering is considered the canonical order to which permutation of the fermions are compared to.
The Fbit class can be viewed as a string of creation operators acting on the vacuum
Our ordering convention is to have the first site of the chain, site , to be the last operator acting on while the last site of the chain, site , is the first operator acting .
When to use Fbit
Fbit can be thought of a way to easily manipulate fermionic states without needing to worry about the fermionic phase accrued when permuting sites. For this reason, Fbit is designed to be useful in workflows involving exact calculations of fermionic systems.
Create an Fbit
There are various ways to construct an Fbit depending on your use case. You can specify the bitstring with a string of 's and 's, the number of sites, and in both cases also pass it a coefficient.
var f1 = Fbit("0101")
var f2 = Fbit("1010",2.0)
var f3 = Fbit(4)
var f4 = Fbit(4,2.0+1.0i)
Extract and Set Fbit Properties
The bitstring, number of sites and coefficient of the Fbit can be set and extracted
var f1 = Fbit("0101")
// get number of sites
print(f1.num_sites())
// set the number of sites
f1.set_num_sites(5);
print(f1.num_sites())
// get and set the coefficient
print(f1.coefficient)
f1.coefficient = 2
print(f1.coefficient)
// get and set the integer representation
print(f1.get_representation())
f1.set_representation(2)
print(f1)
// You can re-initialize the state with a different bit string, length
//and coefficient by calling the constructor.
f1 = Fbit("000") // -> (1+0i)|000>
Setting the integer representation to a new value will not cause changes to the fermionic phase. Instead use the appropriate combination of creation and annihilation operators to change the representation and and obtain the correct fermionic phase.
To efficiently update the bit string of a Fbit you can use binary notation.
var f1 = Fbit(4); // -> (1+0i)|0000>
f.set_representation(0B0010) // -> |0100>
// note this is equivalent to initializing f1 with the string "0100"
Binary notation is written from right to left and returns an integer. When we write our state with a string of 0s and 1s we read the state from left to right. These conventions are flipped deliberately to allow users to think about chains of fermionic degrees of freedom as being indexed from left to right. Care must be taken to account for this convention difference when initializing the integer representation of a Fbit with binary notation.
Because of the binary notation convention used above, the computational basis differs from standard literature. For example, the traditional computational basis state with integer representation is because binary bit strings are read from right to left traditionally. However, in our convention we have that is since we read from left to right. While care is needed in transforming between the two bases, staying in one convention guarantees correctness.
Create and Destroy Fermions
The real power of Fbit lies in the fact that fermions can be moved around without needing to track the phase accrued for anti commuting fermion operators. The phase is calculated every time a creation operator must pass an occupied site and is multiplied into the coefficient of the product state.
To act on the Fbit and/or change the number of fermions, use the create and destroy methods to respectively add a fermion or remove one. Acting on an occupied site with create will annihilate the state, setting the coefficient to zero and does not modify the integer representation. Likewise, the destroy method sets the coefficient to zero if the site it acts upon is empty. Both methods can be done out-of-place by using the past tense of their name.
var f1 = Fbit("1010") // -> (1 + 0i)|1010>
f1.create(1) // -> (-1 + -0i)|1110>
var f2 = f1.created(3) // -> (1 + 0i)|1111>
f2.create(0) // -> (0 + 0i)|1111>
var f3 = Fbit("0101") // -> (1 + 0i)|1010>
f3.destroy(3) // -> (-1 + -0i)|0100>
var f4 = f3.destroyed(1) // -> (-1 + -0i)|0000>
f4.destroy(2) // -> (0 + 0i)|0000>
If a fermion is destroyed on a site that is empty, or is created on an occupied site the coefficient of the Fbit is set to . When writing routines that manipulate Fbits, it's important to check to see if it has been annihilated before using the coefficient in further calculations.
Manipulations on Fbits
Several bit string manipulations can be done on the integer representation stored in the Fbit. These methods do not incur a change in the fermionic phase, they are methods to manipulate bits.
var f1 = Fbit("1100")
f1.translate() // -> (1 + 0i)|0110>
f1.insert(0) // -> (1 + 0i)|00110>
var fs = f1.split(2,3) // -> [(1 + 0i)|00>, (1 + 0i)|110>]
These manipulations are similar to those done on Qbit's and are there to facilitate calculations.
If you want to perform physical manipulations on Fbit's and ensure you get the correct fermionic phase changes, chain create and destroy on your desired state.
Indexing vectors and matrices with Fbit's
Entries of vectors and matrices can be accessed by passing them as indices. This is useful when performing many body computations in the computational basis.
// you can set vector entries with the integer of the Fbit
var q = Fbit("0001")
var vec = zeros([2**q.num_sites], as_complex | as_matrix)
vec[8] = 1
print(vec[q])
// you can likewise pick out matrix entries with psi
var M = random([4,4], as_complex | as_matrix)
var a = Fbit("10")
var b = Fbit("01")
print(M[a,b])
Looping over Fbit's
Loops over Fbit's are a convenient tool for the kinds of calculations present in workflows of fermionic systems where you need to loop over the computational basis states. One way to do this is to do a normal for loop and update the representation of the Fbit
var f = Fbit(6)
for(var rep = 0 ; rep < pow(2,6) ; ++rep)
{
f.set_representation(rep)
// ... do your calculation ...
// reset the coefficient
f.coefficient() = 1.0
}
This for loop method is very explicit and keeps track of a single Fbit object at the cost of potentially needing to reset the coefficient at the end of the loop. A simpler way to for loop over Fbit's are to use the fbit_range object, an iterator object that makes the loop syntax simpler
for(f: fbit_range(6))
{
// ... do your calculation ...
}
which is similar to the first for loop except the fbit object is different at each loop hence there is no need to reset the coefficient.
Best practices
-
Use the in and out of place
createanddestroymethods to manipulate fermions in anFbitas these transformations obey the fermionic anti-commutation relations. -
Fbitobjects are lightweight helpers that supplement dense and sparse state vectors, use them to simplify computational basis state calculations that are otherwise tedious.
Detailed documentation
To check out more detailed documentation see Fbit in the Library Reference.