Monodromy Matrices and Scaled Potentials

Given a real-valued $K$-periodic potential $(v(0),\dots,v(K-1))$, the corresponding monodromy matrix reads

\begin{equation} M = \begin{pmatrix} -v(K-1)&-1\\1&0\end{pmatrix} \begin{pmatrix} -v(K-2)&-1\\1&0\end{pmatrix} \cdots \begin{pmatrix} -v(0)&-1\\1&0\end{pmatrix} \end{equation}

If $v$ is a potential over the alphabet $\Sigma_\lambda = \{0,\lambda\}$ with $\lambda \in \mathbb{R}$, then the corresponding matrix entries of $M$ are polynomials in $\lambda$.

The location of the zeros of the entry $M_{2,1}$ is linked to the invertibility of the corresponding one-sided periodic Schrödinger operator $H_+$. More precisely, if $|\mathrm{tr}(M) | > 2$ and $M_{2,1} \neq 0$, then $H_+$ is invertible.

This notepad will systematically determine all potentials up to length $9$ over the alphabet $\Sigma_0$ and calculate the corresponding monodromy matrices, the zeros of the entry $M_{2,1}$ and the trace of $M$. See the section "Systematic Studies of $\{0, \lambda\}$-Valued Potentials" for details. In particular, all polynomial roots are given by closed-form algebraic expressions.

Data Generation

Run the cell below with Kmin = 1 and Kmax = 9 in order to generate all data for the proofs in the section "Systematic Studies of $\{0, \lambda\}$-Valued Potentials".

The cell will produce a dictionary pots, where the keys are given by stringified potentials and the corresponding values consist of the symbolic monodromy matrix (key='mon'), the zeros of the matrix entry (key='sol') and the value of the trace (key='trace').

Rendering of Output

After all results have been calculated. Run the cell that renders "Human Readable Output".

Interactive Data Analysis

In order to access and further analyse the values in the dictionary for the potential v = [0,1,1] use the syntax

v = [0,1,1]
pots[str(v)]

More examples follow below in the analysis section.

JSON Export

It is possible to export the files in JSON, see the corresponding section at the end of this notebook.

In [1]:
# Run this cell once at startup
###############################

l = var('l')

def mon(v):
##########################
# Calculate the general monodromy matrix with scaling l
#
# Example:
# v = [1,1,0]; mon(v).expand()
# > [      l       1]
# > [l^2 - 1       l]
#
##########################
    M = identity_matrix(2)
    for vv in v:
        M = matrix(2,2,[ - l*vv, -1, 1, 0])*M
    return M

def analyse_v(v):
##########################
# calculate monodromy, zeros and check trace. 
# return a dictionary containing symbolic elements
#
# Example:
# v = [1,1,0]; analyse_v(v)
##########################
    data = {}
#monodromy
    M = mon(v).expand() 
    data['mon'] = M
#zeros
    sols = solve(M[1][0] == 0, l)
    sol = list(map(lambda s: s.rhs(), sols))
    sol.sort()
    data['sol'] = sol
#trace
    data['trace'] = list(map(lambda s: M.trace().subs(l=s), sol))
    return data

#######Data Creation######
# input
Kmin = 1 
Kmax = 8 #maximal period length, not larger than 9 to guarantee algebraic roots
sigma = [0,1] # alphabet 

pots = {} #empty dictionary
for K in range(Kmin,Kmax + 1):
    v_list = Tuples(sigma,K).list() 
    for v in v_list:
        pots[str(v)] = deepcopy(analyse_v(v))

Human Readable Output

The cell below outputs all potentials, their corresponding monodromy matrices, the zeros of the entry M_{1,2}, and the corresponding value of the trace of M. For an interactive data analysis and further documentation, see the cells below.

In [2]:
for k in range(1,9):
    show("Period Length K = ", k)
    v_list = Tuples(sigma,k).list()
    for v in v_list:
        # skip the following potentials for readability 
        # they are treated separately at the the Section
        # "Skipped potentials" of this notebook
        if (v == [1,1,1,1,1,1,1] or v == [1,1,1,1,1,1,0]):
            continue
        show((str(v), pots[str(v)]))

Skipped Potentials

The following cell analyses the previously skipped potentials

v = [1,1,1,1,1,1,0]

and

v = [1,1,1,1,1,1,1]

Both potentials lead to the monodromy matrix entry $M_{1,2}$.

$$ M_{1,2} = l^6 - 5l^4 + 6l^2 - 1 $$

The algebraic roots produced with SageMath don't fully simplify with some remaining expressions that appear to have a non-vanishing imaginary part. The following calculations show that the imaginary parts add up, so that roots are only taken of positive real numbers.

Note that $$ 9 \cdot \left(\frac{7}{18} i \, \sqrt{3} + \frac{7}{54}\right)^{\frac{1}{3}} = 3 \, \sqrt{7} {\left(\cos\left(\frac{1}{3} \, \arctan\left(3 \, \sqrt{3}\right)\right) + i \, \sin\left(\frac{1}{3} \, \arctan\left(3 \, \sqrt{3}\right)\right)\right)} $$

and

$$ \frac{7}{{\left(\frac{7}{18} i \, \sqrt{3} + \frac{7}{54}\right)}^{\frac{1}{3}}} = \left(\cos\left(\frac{1}{3} \, \arctan\left(3 \, \sqrt{3}\right)\right) - i \, \sin\left(\frac{1}{3} \, \arctan\left(3 \, \sqrt{3}\right)\right)\right) $$

This shows that $$ \mathrm{Im} \left( 9 \cdot \left(\frac{7}{18} i \, \sqrt{3} + \frac{7}{54}\right)^{\frac{1}{3}} + \frac{7}{{\left(\frac{7}{18} i \, \sqrt{3} + \frac{7}{54}\right)}^{\frac{1}{3}}} \right) = 0 $$

and

$$ \mathrm{Re} \left( 9 \cdot \left(\frac{7}{18} i \, \sqrt{3} + \frac{7}{54}\right)^{\frac{1}{3}} + \frac{7}{{\left(\frac{7}{18} i \, \sqrt{3} + \frac{7}{54}\right)}^{\frac{1}{3}}} \right) > 0 $$
In [3]:
# Run this cell in order to analyse the roots of
# the monodromy matrices for v = [1,1,1,1,1,1,0]
# and v = [1,1,1,1,1,1,1]
v = [1,1,1,1,1,1,0]
print("Monodromy Matrix M for v = [1,1,1,1,1,1,0]")
show(pots[str(v)]['mon'])
v = [1,1,1,1,1,1,1]
print("Monodromy Matrix M for v = [1,1,1,1,1,1,1]")
show(pots[str(v)]['mon'])
print("Zeros of M_{2,1}")
for s in pots[str(v)]['sol']:
    show(s)
Monodromy Matrix M for v = [1,1,1,1,1,1,0]
Monodromy Matrix M for v = [1,1,1,1,1,1,1]
Zeros of M_{2,1}

Result Filtering

The dictionary pots contains all possible periodic potentials. In order to filter the results we need to do 3 things

  1. create a suitable list of potentials
  2. decide whether we want to filter out candidates that don't fulfill the trace condition
  3. decide whether we want to allow irrational scaling factors

Interpretation of Results

Example 1

v_list = Tuples(sigma,2).list()
for v in v_list:
    print([v, [s for s in pots[str(v)]['sol']],  [s if s in QQ else s.n() for s in pots[str(v)]['trace']]])

gives as first line of output

[[0, 0], [r1], [-2]]

This means that the entry $M_{2,1}$ of monodromy matrix for the potential $v = (0,0)$ is zero for all scalings (r1 corresponds to $\mathbb{R}$) and that the value of the trace of $M$ is always $-2$. The line

[[1, 0], [0], [-2]]

means that the entry $M_{2,1}$ of monodromy matrix for the potential $v = (1,0)$ is zero for the scaling l = 1 and that the value of the trace of $M$ is, in this case, $-2$.

Example 2

Similarly to Example 1, we can look at potentials with period $K = 5$. A line like

[[1, 0, 1, 1, 0], [-1/2*sqrt(2), 1/2*sqrt(2)], [2.12132034355964, -2.12132034355964]]

means that the entry $M_{2,1}$ of monodromy matrix for the potential $v = (1, 0, 1, 1, 0)$ is zero for the tuple of $\left( -\frac{\sqrt{2}}{2}, \frac{\sqrt{2}}{2}\right)$ and that the corresponding values of the trace of $M$ are $(2.12\dots, -2.12\dots)$.

Example 3

Only list potentials such that $M_{2,1}$ has at least one rational zero.

v_list = Tuples(sigma,9).list()
for v in v_list:
    isRational = [s in QQ for s in pots[str(v)]['sol']]
    if True in isRational:
        print([v, [s for s in pots[str(v)]['sol']],  [s if s in QQ else s.n() for s in pots[str(v)]['trace']]])

Example 4

Only list potentials such that $M_{2,1}$ has at least one rational zero and have absolute trace larger than 2.

v_list = Tuples(sigma,9).list()
for v in v_list:
    isRational = [s in QQ for s in pots[str(v)]['sol']]
    if True in isRational:
        isTraceGt2 = [abs(s.n()) > 2 for s in pots[str(v)]['trace']]     
        if True in isTraceGt2:
            print([v, [s for s in pots[str(v)]['sol']],  [s if s in QQ else s.n() for s in pots[str(v)]['trace']]])
In [4]:
# example code, modify as indicated above

v_list = Tuples(sigma,5).list()
for v in v_list:
    print([v, [s.full_simplify() for s in pots[str(v)]['sol']],  [s if s in QQ else s.n() for s in pots[str(v)]['trace']]])
[[0, 0, 0, 0, 0], [], []]
[[1, 0, 0, 0, 0], [], []]
[[0, 1, 0, 0, 0], [], []]
[[1, 1, 0, 0, 0], [-1, 1], [2, -2]]
[[0, 0, 1, 0, 0], [], []]
[[1, 0, 1, 0, 0], [], []]
[[0, 1, 1, 0, 0], [], []]
[[1, 1, 1, 0, 0], [-1, 1], [2, -2]]
[[0, 0, 0, 1, 0], [], []]
[[1, 0, 0, 1, 0], [-1, 1], [2, -2]]
[[0, 1, 0, 1, 0], [], []]
[[1, 1, 0, 1, 0], [-1/2*sqrt(2), 1/2*sqrt(2)], [2.12132034355964, -2.12132034355964]]
[[0, 0, 1, 1, 0], [-1, 1], [2, -2]]
[[1, 0, 1, 1, 0], [-1/2*sqrt(2), 1/2*sqrt(2)], [2.12132034355964, -2.12132034355964]]
[[0, 1, 1, 1, 0], [-1, 1], [2, -2]]
[[1, 1, 1, 1, 0], [-sqrt(1/2*sqrt(5) + 3/2), -sqrt(-1/2*sqrt(5) + 3/2), sqrt(-1/2*sqrt(5) + 3/2), sqrt(1/2*sqrt(5) + 3/2)], [-2.00000000000000, 2.00000000000000, -2.00000000000000, 2.00000000000000]]
[[0, 0, 0, 0, 1], [], []]
[[1, 0, 0, 0, 1], [], []]
[[0, 1, 0, 0, 1], [], []]
[[1, 1, 0, 0, 1], [-1, 1], [2, -2]]
[[0, 0, 1, 0, 1], [], []]
[[1, 0, 1, 0, 1], [], []]
[[0, 1, 1, 0, 1], [], []]
[[1, 1, 1, 0, 1], [-1, 1], [2, -2]]
[[0, 0, 0, 1, 1], [], []]
[[1, 0, 0, 1, 1], [-1, 1], [2, -2]]
[[0, 1, 0, 1, 1], [], []]
[[1, 1, 0, 1, 1], [-1/2*sqrt(2), 1/2*sqrt(2)], [2.12132034355964, -2.12132034355964]]
[[0, 0, 1, 1, 1], [-1, 1], [2, -2]]
[[1, 0, 1, 1, 1], [-1/2*sqrt(2), 1/2*sqrt(2)], [2.12132034355964, -2.12132034355964]]
[[0, 1, 1, 1, 1], [-1, 1], [2, -2]]
[[1, 1, 1, 1, 1], [-sqrt(1/2*sqrt(5) + 3/2), -sqrt(-1/2*sqrt(5) + 3/2), sqrt(-1/2*sqrt(5) + 3/2), sqrt(1/2*sqrt(5) + 3/2)], [-2.00000000000000, 2.00000000000000, -2.00000000000000, 2.00000000000000]]

JSON Output

Export the pots dictionary in JSON file format.

You can read the input using a simple Python program

#!/bin/python3

import json

with open('pots_export.json') as json_file:
    data = json.load(json_file)
    for key in data:
        print(key)

or an online JSON reader like https://jsonformatter.org/json-reader .

In [5]:
# run this cell to in order to save pots into json file

import json
def jsonify_dict(input_dict):
##########################
# create json object from dictionary, 
# stringify everything for serialization
##########################
    json_object ={}
    for key in input_dict:
        dictionary = {}
        dictionary['mon'] = str(input_dict[key]['mon'])
        dictionary['sol'] = str(input_dict[key]['sol'])
        dictionary['trace'] = str(input_dict[key]['trace'])
        json_object[str(key)] = deepcopy(dictionary)
    return json_object

json_dict = jsonify_dict(pots)

with open('pots_export.json', 'w') as outfile:
    json.dump(json_dict,outfile)