{'fraction_non_alphanumeric': 0.031119218800300462, 'fraction_numerical': 0.004006152305326037, 'mean_word_length': 5.007305543618393, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
A Generic Approach to Electronic Structure Calculations in Nanoscopic Systems

We outline a generic, flexible, modular, yet efficient framework to the computation of energies and states for general nanoscopic systems with a focus on semiconductor quantum dots. The approach utilizes the configuration interaction method, in principal obtaining all many-body correlations in the system. The approach exploits the powerful abstracting mechanisms of C++'s template facility to produce efficient yet general code. The primary utility of the present approach is not in the resulting raw computational speed, but rather in minimizing the time from initial idea to final results.


Introduction
The configuration interaction (CI) approach to electronic structure calculations has the benefit of being conceptually simple and the capability of being potentially exact-exact in the sense that all eigenstates and energies of the given model system can be exactly computed given sufficient computational resources. The detriment of the CI method is the great resources it requires. Generally speaking, state of the art calculations perform at 8-10 particles. The reason is that the CI method is essentially a direct diagonalization of the system's Hamiltonian matrix, and the size of this matrix grows (at least) exponentially with the number of particles.
Because of this, other techniques, such as quantum Monte Carlo (QMC) and density functional theory, in all their various guises, are often employed (and often required) in place of CI calculations. Of these, QMC and CI methods are the two primary tools in cases where correlations are strong, where excited states in addition to ground states are required, and especially where the many-body states themselves (as opposed to the energies) are required. QMC has great potential for being far more efficient than CI, yet is also far more complex both in concept and in practical aspects of coding. Thus, QMC may be viewed as being well suited for problems where a large number of particles is required, or for stable production code which will be applied to a specific fixed set of systems over a prolonged period of time.
One may distinguish, however, between fast code written slowly-that is, taking a long time to code, test, debug, and maintain-and slow code written quickly. QMC belongs in the former category, while CI belongs in the latter. Particularly for basic research, and perhaps less so for applied research, a more useful interpretation of "efficiency" than the actual computation time is to include development time as well. Often, the most relevant time is that between initial idea and final result, and by no means is this duration necessarily dominated by raw computation time. In this sense, a properly structured CI base can be an important piece of a research framework, particularly when flexibility is highly desired.

The need for a flexible computing environment
Flexibility is particularly required for computations involving the basic physics of synthetic nanostructures such as semiconductor quantum dots. 1 There are four main reasons for this: the nonuniversality of synthetic structures, the insufficiency of ab initio methods for large systems, the many different environmental couplings in heterogeneous solid-state devices, and the highly tunable symmetries experimentally attainable. In this section, we explore these issues by comparing them to atomic systems, where very robust and highly efficient code is available.
In semiconductor quantum dots-for example, artificial atoms 2 defined by electrostatic (lateral) confinement of electrons in a two-dimensional electron gas-each manufactured device is unique and, for example, the confining potential of two devices with ostensibly identical gate geometries and identical numbers of confined particles, will nevertheless have unique confining potentials, tunneling barriers, and other parameters significantly affecting the transport, electronic, and spin properties of the device. Contrast this with atoms, where every distinct atomic species is an indistinguishable particle; a large-scale, robust, sophisticated, and efficient code base 3 eventually pays off since the resulting application is indefinitely applicable to all future problems of the same atomic species.
In addition to the non-uniqueness of synthetic structures, many are also large in size, and can contain, for example, several millions of different atomic species arranged in heterogeneous geometries. Not only are current ab initio methods insufficient to deal with nonperiodic systems of such size, but often they are also undesirable; numerical results on simpler effective Hamiltonians many times yield more insightful, more intuitive results, particularly when studying experimentally observed effects (decoherence, for example) whose underlying physical mechanisms are unknown. In such cases, numerical results are more properly viewed as aids to theoretical analysis rather than pure simulation.
In quantum nanoelectronic systems, and mesoscopic systems more generally, the relevant length scale of the constituent particles-for example, their de Broglie wavelength, or their mean free path-extends over the dimensions of the confinement potential. In such cases, boundary effects or other couplings to various environments often drive the observed physics. These couplings generally destroy quantum diagon A generic approach to electronic structure calculations in nanoscopic systems 3 coherence and lead the system to more classical-like behavior. Experiments can now probe this boundary between classical and quantum physics and the relevant physics can often times be explored only numerically. A numerical approach must be flexible enough to investigate these quantum statistical systems, neither periodic nor isolated, coupled to a heterogeneous and fluctuating environment, and driven far from equilibrium. Such a purely quantum numerical framework does not currently exist. Indeed even the basic physical theory is often poorly understood. In such cases, particularly when only a few interacting electron are present (but infinite bath degrees of freedom), flexibility usually (not always) trumps raw processing power.

The choice of programming language
In terms of raw speed, simpler languages are usually superior. This, along with simple inertia, likely explains the dominance, or at least the preponderance, of fortran for numerical code. But, generally speaking, simpler implies less expressive which in turn implies less flexible. If flexibility is to be put at a premium, then a more expressive language is required. This will generally come at a cost of slower speed, but quicker development.
A practical compromise is a language where the programmer can decide how much of an abstraction penalty to pay. This pay-only-for-what-you-use approach is well represented in the C++ programming language, and this is the language in which we have developed the Diagon 4 framework we describe below.
More important than efficiency, more important than flexibility, correctness is the single most important requirement of all numerical code. An aid, but by no means a savior, to correctness is C++'s type safety. A constant can really be a constant without recourse to preprocessor macros. Pointers can point to (various) constant objects or can be constant pointers themselves. Parameters to functions can be passed by value, by reference, or, most efficiently, by constant reference. These often obviate the need for raw pointers to memory and all their error prone complexity. Authors of a class have at their disposal (and their discretion) a great deal of control over how memory is precisely allocated, and how objects are created, assigned, copied, or converted to other types. These language features are great tools in producing flexible yet robust numerical frameworks.

Generic programming
None of the above has anything to do with object-oriented programming-the paradigm most frequently associated with C++. Indeed C++ supports several programming styles, including procedural and functional, as well as object-oriented. However, in our opinion, the single most useful feature of C++ in regards to numerical computation is its generic programming facilities. These can be seen as a bridge between expressiveness on the one hand, and efficiency on the other. Particularly for scientific programming, recent developments 5 in generic programming have clearly shown that flexibility and abstraction need not necessarily incur a run-time penalty and have moved the state of the art far beyond simple parametrized types.
At its most basic level, generic programming separates data types from algorithms. 6 Thus, for example, a single sort algorithm can be written that can sort objects of arbitrary type, including user-defined classes, so long as the expression A < B is defined for objects of those types. And because of operator overloading, the less-than operator can be defined by the author of the data type. Because of this, generic programming can be said to make code forwards compatible in time, rather than simply backwards compatible with previous versions. If a specific type requires a more efficient algorithm, that particular type can be made into a special case through partial template specialization.
Importantly, this great flexibility can come with little or no performance penalty-a crucial difference compared to dynamically typed languages such as Python or Ruby. The C++ generic facilities produce statically typed compiled code. In effect, a generic template function is a program that writes programs and is essentially a type-safe meta-programming facility. Upon compilation, the compiler takes a template function, and instantiates a specific version for whatever data type is required. Thus, a single sort template function can produce several custom-made (by the compiler) versions in the executable; one each for, say, integers, doubles, complex numbers, or many-body state vectors sorted by energy. The important fact is that this happens at compile time, not run time, and so the produced code can be very efficient. The compiler can turn this single function into an unbounded number of functions operating on types which the original author could not have conceived.
The Diagon framework we describe below really only scratches the surface of what generic programming can do. For example, templates can be used to keep track of dimensional quantities, 7 so that, for example, the system knows that length/time is a velocity and can give a (compile-time) error when a length is assigned to a velocity, even though all quantities are, say doubles. In fact, scientific programmers recognized quite early on 8 the benefits of generic programming.
As an example of the flexibility of generic programming coupled with function overloading, we give here an example of their use in the Diagon framework which we discuss more fully below. Specifically, we can consider the inner product of various state vectors describing electrons in a quantum dot. There are at least three types of states that are generally required. At the single-particle level, there are the base single-particle orbital states |α , where α denotes a full set of quantum numbers, which we label generically as SPState. A many-body Fermion system is described by antisymmetrised vectors |α 0 , α 1 , α 2 , . . . (Slater determinants, labeled AntiSymmState) in accordance with the Pauli exclusion principle. Thirdly, correlated states |ψ = i c i |α i 0 , α i 1 , α i 2 , . . . (induced by Coulomb interactions or spin symmetry 9 ) require a description in terms of coherent superpositions of Slater determinants, LinCombState.
The inner product of SPState's clearly depends on the the particular system under consideration. However, the algorithmic computation of inner products of either LinCombState's or AntiSymmState's is essentially identical and independent of the underlying SPState. Thus, once supplied with an inner product function for the particular SPState, the calculation for inner products involving more complex state vectors can proceed automatically, without a need for rewriting the functions. The object-oriented solution to this problem is to define a class hierarchy and to pass pointers (or references) to the functions. At run time, the appropriate inner product will be called. Besides the extra (run-time) cost involved in dereferencing objects for dynamic polymorphism, this approach will almost certainly lead to an ever-growing hierarchy of states, with commensurate costs in maintenance and testing. In addition, the core code base requires altering with every new SPState introduced to the system; as the number of states known to the system grows, maintenance, and continued testing for correctness, becomes more and more of a burden.
In a generic approach, the code base remains small. Here, one defines generic containers AntiSymmState<SPState> and LinCombState<State> a which can hold any type of state. Provided the user implements a set of SPState's and defines single-particle inner-product functions, then inner products involving many-body states need not be (re)written; the compiler will write a custom version of the appropriate inner product function. The template functions themselves indicate the algorithm, not the data types.
Because generic components can be combined as required, a small set of generic components are capable of producing combinatorially many functions. Thus, with a small set of components, a large array of composite objects can be defined, maximizing the flexibility of the numerical approach. This flexibility need not incur a run-time penalty; all template instantiations are implemented at compile-time. This is a tremendous advantage both in the speed of developing a custom application from a set of generic components, as well as in maintaining efficient code at run time.
We have implemented such a generic framework, Diagon, for computing eigenstates and eigenvalues of semiconductor quantum dots for arbitrary potentials, with arbitrary numbers of particles, and arbitrary Hamiltonians. This is a framework, meant for developing applications rather than a tool for end users. We describe the framework below and show that it can be used to build flexible and extensible applications without undue sacrifice on run-time efficiency.

The Diagon Framework
The Diagon 4 framework consists of a set of generic components useful in the manipulation of many-body quantum states and computations involving them. There are a Note that a LinCombState can describe linear combinations of AntiSymmState's with different sizes. This would be required when particle number is not conserved, as, for example, when studying transport through a quantum dot. 10 currently components for dealing with various types of Fermion states, components for computing matrix elements of one and two-body operators, generators returning proper spin eigenstates given a set of singly and doubly occupied single-particle orbitals, and components for computing eigenstates and eigenvalues of Hermitian operators. These components are all generic and the single-particle states themselves need to be provided. We give in this section an overview of the Diagon components. In the following section, we provide an example calculation for calculating spectra and states of two-dimensional parabolic dots with spin-orbit interactions.

Generic quantum many-body states
There are three classes of many-body states: AntiSymmState<SPState> is the primary class for antisymmetrised product states. In real space, these are Slater determinants. Upon instantiation, the (generic) parameter SPState must name an existing class encapsulating a known single-particle state. For example, in two dimensional parabolically-confined quantum dots, the single particle states may be the well-known Fock-Darwin 11 states |mns . Typically, the inner product between these two single-particle states will also be provided. In the Fock-Darwin case, we simply have n ′ m ′ s ′ |nms = δ ss ′ δ nn ′ δ mm ′ . Operations are provided for creating and destroying particles in these states, as well as computing inner products if supplied with the inner product for the underlying single-particle states.
In addition to the (user provided) single-particle states and the (Diagon provided) AntiSymmState's, a generic class LinCombState<State, Coeff> is provided for encoding linear superpositions of states, |LinCombState = α c α |α . Here, the template parameter State is the type of component states (which can be, for example, SPState's or AntiSymmState's) and Coeff is a template parameter encoding the type of the coefficients, which will usually be real or complex numbers, but, since the class is generic, could be of more exotic type. Operations are provided for adding and removing terms from the sum, for checking and setting normalization of the state as a whole, for indexing a particular term, and for iterating over all terms. If class State defines an inner product, then LinCombState|LinCombState and LinCombState|State are both defined.
The final class of many-body states is the StateSet<State, Coeff> class. This class encapsulates a set of LinCombState<State, Coeff>'s which all share a common basis. It is used, for example, as a return type from a diagonalization routine where each LinCombState is an eigenstate. It can also be used to describe a set of spin eigenstates. (See Sec. 4.3.) Operations are provided, for example, to add or remove a basis vector to the StateSet, or to add or remove a LinCombState.
With the above three generic components, one need only define a particular single-particle state and an inner product, and many-body states and linear superpositions of them are made available, and a full suite of inner products and other manipulations and computations are made available. diagon A generic approach to electronic structure calculations in nanoscopic systems 7

Generic operator functions
A general quantum operatorÔ can be given a matrix form with elements ψ i |Ô|ψ j , with i, j running over all basis vectors which can be SPState's, AntiSymmState's, or LinCombState's. The Diagon framework provides generic operators for both one and two body operators.
A general one-body operator can be written in second quantized form aŝ where c † p creates a particle in state |p . In the Diagon framework, matrix elements of the operatorÔ are implemented generically as oneBodyOp(bra, ket, matelem).
Here, bra and ket can be any (combination) of the three basic types of states in Sec. 4.1, and matelem is a user-defined function evaluating O pq in Eq. (1). That is, matelem must have signature
We see that once the user defines single-particle properties, which will be different from system to system, the Diagon framework implements the many-body functionality, which is in a sense a universal function of the single-particle physics.
Two-body operators are implemented generically in a similar way. A difference now is how spin is treated. In particular, any spin-independent two-body operator (e.g., the Coulomb interaction) can be written aŝ where the U ijkl = (ij|Û |kl) are the coefficients 12 which must be provided by the user, with all indices i, j, k, l denoting single-particle states. This is again implemented as twoBodyOp(bra, ket, matelem) but the two states must now contain at least two particles (AntiSymmState's or LinCombState's) and matelem must have signature ReturnType matelem(SPState bra1, SPState bra2, SPState ket1, SPState ket2).
The generic function twoBodyOp returns whatever matelem returns.
In Sec. 5, we describe a specific example using the above generic components. Before we do, however, we discuss generic facilities Diagon provides for computing eigenstates of total spin and other more general Hermitian operators.

Generic spin states
Because the CI technique is so computationally intensive, it is important to take advantage of every significant symmetry in the system as this affords a possibility to block-diagonalize the Hamiltonian matrix, drastically reducing the computational load. Simple symmetries such as conservation of spin or angular-momentum projection along a given axis (S z tot or L z tot , say) are simple to implement since these symmetries do not produce correlations and their conservation can always be encoded in a single Slater determinant. Other symmetries-total spin, S 2 tot , being the most prominent-do induce correlations, and a single Slater determinant (AntiSymmState) cannot in general be written down in which S 2 tot is a good quantum number.
In such cases, a correlated basis may be used which preserves the many-body symmetry. This, in general, would require a prediagonalization step. 13 However, the SU(2) symmetry of spin, along with its higher-dimensional representations, allows all eigenstates of spin to be written down for arbitrary orbital configuration, essentially relying on the appropriate products of Clebsch-Gordon coefficients. 14,15 Such a facility is provided in Diagon through the spinGen generic function, spinGen(AntiSymmState<SPState> config, int twoS, int twoSz), which returns a StateSet. (See Sec. 4.1.) Each element of the StateSet is a LinCombState<AntiSymmState<SPState>> which is an eigenstate of S 2 tot with the appropriate spin quantum number. Input to spinGen is two times the spin S and two times the projection S z . (This is to keep the inputs integers.) Input is also the orbital configuration as an AntiSymmState<SPState>.

Generic diagonalization
The CI method eventually requires a diagonalization. Currently, Diagon employs the uBLAS linear algebra library of the Boost b project, along with a bindings library allowing C++ to directly interface with the LAPACK algorithms. This can be extended to other diagonalization routines without much trouble. To construct H, one would normally call oneBodyOp and/or twoBodyOp for each of the elements. To aid in this, a function matrixOp is provided

Matrix matrixOp(basis, matelem)
which returns the uBLAS matrix obtained by applying matelem (Sec. 4.2) to each of the basis vectors in basis. This function calls oneBodyOp and twoBodyOp as appropriate.
As mentioned above, the primary purpose of the Diagon framework is to provide flexible, generic tools to aid development. This aspect was placed at a higher premium than pure computational efficiency, although the generic nature of the framework is very well suited to producing efficient code as well. In the following penultimate section, we provide an example illuminating the strengths of the Diagon framework.

Example: Parabolic dots with spin-orbit interactions
Using the generic framework Diagon, a complete diagonalization program can be set up and run remarkably quickly. Once the basic (non-generic) components are provided, the package, at compile-time, produces a custom-made set of classes and functions dealing with linear superpositions of many-body states. These can be used as a simple diagonalization to obtain spectra, or the eigenstates can be used for further computations in, for example, problems of quantum dynamics and decoherence, where the actual states are required, and where correlations in the system play an important role. In this section, we outline a diagonalization procedure to illustrate the use of the Diagon framework.
We look specifically with at a two-dimensional quantum dot in a GaAs/AlGaAs heterojunction parabolically confined in the plane and in the presence of both spinorbit interactions and a magnetic field perpendicular to the plane of the dot. 11 The Hamiltonian may be written asĤ where the quantum dot Hamiltonian is given by two harmonic oscillators plus a Zeeman termĤ with Ω ± = [(ω 2 c + 4ω 2 0 ) 1/2 ± 1]/2. Here, ω 0 is the confinement frequency characterizing the parabolic confinement, 11 and ω c = eB z /(mc) is the cyclotron frequency. The final term in Eq. (3) is the spin-orbit interaction. We take a lin- earized model including both Dresselhaus and Rashba terms, 16 respectively given byĤ so = β(−σ x p x + σ y p y ) + α(σ y p x − σ x p y ), where σ k are the Pauli matrices, and β and α are respectively the Dresselhaus and Rashba coefficients. In terms of the Bose operators of Eq. (4), we can writê where h.c. is the Hermitian conjugate, S + is the spin raising operator, and Λ 2 = ( m/2)/(ω 2 c + 4ω 2 0 ) 1/2 . The objective in this example is to diagonalize Eq. (3) in the basis of the eigenstates of Eq. (4), given by the well-known 11 Fock-Darwin states |nms . Figure 1 shows a minimal function which does this using the Diagon framework. The example is meant only for illustrative purposes; header files and additional comments have been stripped for brevity. Section 1 of the code simply creates parameters for Eq. (4); the genFDParamGaAs() function takes ω 0 and the external field and computes Ω ± and the Zeeman energy in Eq. (4) using GaAs material parameters. Section 2 performs a similar task for Eq. (5).
Section 3 generates the basis states with which to perform the diagonalization. The object fdGen() is a function which is instantiated with the fdParam object; successive calls of fdGen() return the Fock-Darwin state |nms with the next-diagon A generic approach to electronic structure calculations in nanoscopic systems 11 highest energy. Thus calling fdGen() 1000 times will yield the 1000 lowest-energy states with the given material and model parameters. The line generate(basisStates.begin(), basisStates.end(), fdGen); does exactly this. The basis states are then stored in the vector basisStates.
Section 4 of Fig. 1 creates the Hamiltonian matrix, Eq. (3), using the matrixOp function of Sec. 4.4. The function objects fdMatElem and fdMatElemSO are each to be called with two arguments (Fock-Darwin states, FDState) and return matrix elements ofĤ qd andĤ so respectively. Thus, these are the matelem objects described in Sec. 4.2.
Finally, in section 5 of Fig. 1, the diagonalization occurs. A StateSet (Sec. 4.1) is first created and the basis states are added to it. Then, diagon (Sec. 4.4) is called and the eigenvalues are placed in the vector eigenValues, whereas all the eigenstates, each an orthogonal superposition of the basis vectors, are placed in the StateSet eigenVectors. These results can then be printed, or otherwise processed.
We stress that this simple example is meant for illustrative purposes only. Many of the functions in Fig. 1 take optional arguments and support different interfaces and much of the Diagon framework has not been explicitly mentioned in this example. Nevertheless, it does illustrate how a properly constructed generic framework can support a flexible computing environment. For example, elliptic dots could easily be added to the above example. One would simply need to define an additional matelem function object which computes the appropriate matrix elements, and an additional parameter object containing the eccentricities and so forth. This additional term could then be added to the Hamiltonian through the matrixOp function. Additionally adding Coulomb interactions among the particles would proceed along essentially identical lines.

Conclusions
We have outlined an approach to the CI method which utilizes the generic programming facilities provided by the C++ programming language. The general idea is that much of the CI machinery is independent of the actual single-particle states used. A generic approach allows one explicitly separate algorithms and data types and allows a great deal of code reuse. This has been implemented in the Diagon framework, which focuses on (but is by no means restricted to) two-dimensional semiconductor quantum dots. A generic approach such as this offers a good compromise between rapid development and flexibility on the one hand, and efficient code on the other.