"""
    fgsm_s(R, chars)

Compute the Sᵢⱼ's in FGSM, without taking the product over the choices of the signs of the square roots. Return the smallest absolute value of the FGSM relations.
"""
function fgsm_s(R, chars)
    z = zeros(5);
    theta_constants = [[theta(z, R, char=c) for c in chars_s] for chars_s in chars];
    p = [sqrt(prod(theta_constant)) for theta_constant in theta_constants];
    S = collect(Iterators.flatten([p[1] + i2*p[2] + i3*p[3] + i4*p[4] + i5*p[5] + i6*p[6] for i2 in [1,-1], i3 in [1,-1], i4 in [1,-1], i5 in [1,-1], i6 in [1,-1]]));
    min_fgsm = minimum(abs.(S));
    return min_fgsm;
end

"""
    fgsm(τ, chars=fgsm_chars())

Compute the FGSM relations in genus 5. Return the largest absolute value of the relation.
"""
function fgsm(τ::Array{<:Number}, chars=fgsm_chars())
    R = RiemannMatrix(τ, nderivs=0);
    return fgsm(R, chars);
end

"""
    fgsm(R, chars=fgsm_chars())

Compute the FGSM relations in genus 5. Return the largest absolute value of the relation.
"""
function fgsm(R::RiemannMatrix, chars=fgsm_chars())
    max_fgsm = maximum([fgsm_s(R, c) for c in chars]);
    return max_fgsm;
end


"""
    random_nonfgsm(tol=0.1, trials=100)

Find a random genus 5 matrix in the Siegel upper half space which is not in the FGSM locus, such that the largest FGSM relation has absolute value at least tol, using input number of trials.
"""
function random_nonfgsm(tol::Real=0.1, trials::Integer=100)
    chars = fgsm_chars();
    t = 0; # stores value of largest FGSM relation encountered
    i = 0; # counter for number of trials
    max_matrix = rand(5,5); # stores candidate matrix
    while t < tol && i < trials
        τ = random_siegel(5);
        s = fgsm(τ, chars);
        if s > t
            t = s;
            max_matrix = τ;
        end
        i += 1;
    end
    return [max_matrix, t];
end

"""
    fgsm_chars()

Compute the characteristics used in the FGSM relations in genus 5.
"""
function fgsm_chars()
    chars_34 = [[[[0,0,0,0,0], [0,0,0,0,0]],
                 [[0,0,0,0,0], [1,1,1,1,1]],
                 [[0,0,1,1,0], [0,1,0,0,0]],
                 [[0,0,1,1,0], [1,0,1,1,1]],
                 [[1,1,0,0,0], [0,0,0,1,0]],
                 [[1,1,0,0,0], [1,1,1,0,1]],
                 [[1,1,1,1,0], [0,1,0,1,0]],
                 [[1,1,1,1,0], [1,0,1,0,1]]],
                [[[1,0,1,0,0], [0,0,0,0,0]],
                 [[1,0,1,0,0], [1,1,1,1,1]],
                 [[1,0,0,1,0], [0,1,0,0,0]],
                 [[1,0,0,1,0], [1,0,1,1,1]],
                 [[0,1,1,0,0], [0,0,0,1,0]],
                 [[0,1,1,0,0], [1,1,1,0,1]],
                 [[0,1,0,1,0], [0,1,0,1,0]],
                 [[0,1,0,1,0], [1,0,1,0,1]]],
                [[[0,0,0,0,0], [0,0,1,1,0]],
                 [[0,0,0,0,0], [1,1,0,0,1]],
                 [[0,0,1,1,0], [0,1,1,1,0]],
                 [[0,0,1,1,0], [1,0,0,0,1]],
                 [[1,1,0,0,0], [0,0,1,0,0]],
                 [[1,1,0,0,0], [1,1,0,1,1]],
                 [[1,1,1,1,0], [0,1,1,0,0]],
                 [[1,1,1,1,0], [1,0,0,1,1]]],
                [[[1,0,0,0,1], [0,0,0,0,0]],
                 [[1,0,0,0,1], [1,1,1,1,1]],
                 [[1,0,1,1,1], [0,1,0,0,0]],
                 [[1,0,1,1,1], [1,0,1,1,1]],
                 [[0,1,0,0,1], [0,0,0,1,0]],
                 [[0,1,0,0,1], [1,1,1,0,1]],
                 [[0,1,1,1,1], [0,1,0,1,0]],
                 [[0,1,1,1,1], [1,0,1,0,1]]],
                [[[0,0,1,0,1], [0,0,0,0,0]],
                 [[0,0,1,0,1], [1,1,1,1,1]],
                 [[0,0,0,1,1], [0,1,0,0,0]],
                 [[0,0,0,1,1], [1,0,1,1,1]],
                 [[1,1,1,0,1], [0,0,0,1,0]],
                 [[1,1,1,0,1], [1,1,1,0,1]],
                 [[1,1,0,1,1], [0,1,0,1,0]],
                 [[1,1,0,1,1], [1,0,1,0,1]]],
                [[[1,0,0,0,1], [0,0,1,1,0]],
                 [[1,0,0,0,1], [1,1,0,0,1]],
                 [[1,0,1,1,1], [0,1,1,1,0]],
                 [[1,0,1,1,1], [1,0,0,0,1]],
                 [[0,1,0,0,1], [0,0,1,0,0]],
                 [[0,1,0,0,1], [1,1,0,1,1]],
                 [[0,1,1,1,1], [0,1,1,0,0]],
                 [[0,1,1,1,1], [1,0,0,1,1]]]];
    chars_35 = [[[[0,0,0,0,0], [0,0,0,0,0]], 
                 [[0,0,0,0,0], [1,1,1,1,1]], 
                 [[0,0,1,0,1], [0,1,0,0,0]], 
                 [[0,0,1,0,1], [1,0,1,1,1]],
                 [[1,1,0,0,0], [0,0,0,0,1]],
                 [[1,1,0,0,0], [1,1,1,1,0]],
                 [[1,1,1,0,1], [0,1,0,0,1]],
                 [[1,1,1,0,1], [1,0,1,1,0]]],
                [[[1,0,1,0,0], [0,0,0,0,0]],
                 [[1,0,1,0,0], [1,1,1,1,1]],
                 [[1,0,0,0,1], [0,1,0,0,0]],
                 [[1,0,0,0,1], [1,0,1,1,1]],
                 [[0,1,1,0,0], [0,0,0,0,1]],
                 [[0,1,1,0,0], [1,1,1,1,0]],
                 [[0,1,0,0,1], [0,1,0,0,1]],
                 [[0,1,0,0,1], [1,0,1,1,0]]],
                [[[0,0,0,0,0], [0,0,1,0,1]],
                 [[0,0,0,0,0], [1,1,0,1,0]],
                 [[0,0,1,0,1], [0,1,1,0,1]],
                 [[0,0,1,0,1], [1,0,0,1,0]],
                 [[1,1,0,0,0], [0,0,1,0,0]],
                 [[1,1,0,0,0], [1,1,0,1,1]],
                 [[1,1,1,0,1], [0,1,1,0,0]],
                 [[1,1,1,0,1], [1,0,0,1,1]]],
                [[[1,0,0,1,0], [0,0,0,0,0]], 
                 [[1,0,0,1,0], [1,1,1,1,1]], 
                 [[1,0,1,1,1], [0,1,0,0,0]], 
                 [[1,0,1,1,1], [1,0,1,1,1]],
                 [[0,1,0,1,0], [0,0,0,0,1]],
                 [[0,1,0,1,0], [1,1,1,1,0]],
                 [[0,1,1,1,1], [0,1,0,0,1]],
                 [[0,1,1,1,1], [1,0,1,1,0]]],
                [[[0,0,1,1,0], [0,0,0,0,0]],
                 [[0,0,1,1,0], [1,1,1,1,1]],
                 [[0,0,0,1,1], [0,1,0,0,0]],
                 [[0,0,0,1,1], [1,0,1,1,1]],
                 [[1,1,1,1,0], [0,0,0,0,1]],
                 [[1,1,1,1,0], [1,1,1,1,0]],
                 [[1,1,0,1,1], [0,1,0,0,1]],
                 [[1,1,0,1,1], [1,0,1,1,0]]],
                [[[1,0,0,1,0], [0,0,1,0,1]],
                 [[1,0,0,1,0], [1,1,0,1,0]],
                 [[1,0,1,1,1], [0,1,1,0,1]],
                 [[1,0,1,1,1], [1,0,0,1,0]],
                 [[0,1,0,1,0], [0,0,1,0,0]],
                 [[0,1,0,1,0], [1,1,0,1,1]],
                 [[0,1,1,1,1], [0,1,1,0,0]],
                 [[0,1,1,1,1], [1,0,0,1,1]]]];
    chars_45 = [[[[0,0,0,0,0], [0,0,0,0,0]], 
                 [[0,0,0,0,0], [1,1,1,1,1]], 
                 [[0,0,0,1,1], [0,1,0,0,0]], 
                 [[0,0,0,1,1], [1,0,1,1,1]],
                 [[1,1,0,0,0], [0,0,0,0,1]],
                 [[1,1,0,0,0], [1,1,1,1,0]],
                 [[1,1,0,1,1], [0,1,0,0,1]],
                 [[1,1,0,1,1], [1,0,1,1,0]]],
                [[[1,0,0,1,0], [0,0,0,0,0]],
                 [[1,0,0,1,0], [1,1,1,1,1]],
                 [[1,0,0,0,1], [0,1,0,0,0]],
                 [[1,0,0,0,1], [1,0,1,1,1]],
                 [[0,1,0,1,0], [0,0,0,0,1]],
                 [[0,1,0,1,0], [1,1,1,1,0]],
                 [[0,1,0,0,1], [0,1,0,0,1]],
                 [[0,1,0,0,1], [1,0,1,1,0]]],
                [[[0,0,0,0,0], [0,0,0,1,1]],
                 [[0,0,0,0,0], [1,1,1,0,0]],
                 [[0,0,0,1,1], [0,1,0,1,1]],
                 [[0,0,0,1,1], [1,0,1,0,0]],
                 [[1,1,0,0,0], [0,0,0,1,0]],
                 [[1,1,0,0,0], [1,1,1,0,1]],
                 [[1,1,0,1,1], [0,1,0,1,0]],
                 [[1,1,0,1,1], [1,0,1,0,1]]],
                [[[1,0,1,0,0], [0,0,0,0,0]], 
                 [[1,0,1,0,0], [1,1,1,1,1]], 
                 [[1,0,1,1,1], [0,1,0,0,0]], 
                 [[1,0,1,1,1], [1,0,1,1,1]],
                 [[0,1,1,0,0], [0,0,0,0,1]],
                 [[0,1,1,0,0], [1,1,1,1,0]],
                 [[0,1,1,1,1], [0,1,0,0,1]],
                 [[0,1,1,1,1], [1,0,1,1,0]]],
                [[[0,0,1,1,0], [0,0,0,0,0]],
                 [[0,0,1,1,0], [1,1,1,1,1]],
                 [[0,0,1,0,1], [0,1,0,0,0]],
                 [[0,0,1,0,1], [1,0,1,1,1]],
                 [[1,1,1,1,0], [0,0,0,0,1]],
                 [[1,1,1,1,0], [1,1,1,1,0]],
                 [[1,1,1,0,1], [0,1,0,0,1]],
                 [[1,1,1,0,1], [1,0,1,1,0]]],
                [[[1,0,1,0,0], [0,0,0,1,1]],
                 [[1,0,1,0,0], [1,1,1,0,0]],
                 [[1,0,1,1,1], [0,1,0,1,1]],
                 [[1,0,1,1,1], [1,0,1,0,0]],
                 [[0,1,1,0,0], [0,0,0,1,0]],
                 [[0,1,1,0,0], [1,1,1,0,1]],
                 [[0,1,1,1,1], [0,1,0,1,0]],
                 [[0,1,1,1,1], [1,0,1,0,1]]]];
    return [chars_34, chars_35, chars_45];
end



