<reponame>joshmaglione/SingularZeta
#
#   Copyright 2020 <NAME> 
#
#   Distributed under MIT License
#


from rationalPoints import _guess_polynomial
from globalVars import _DEFAULT_VERBOSE as _verbose

# A useful function for multiple lines
_cat_with_space = lambda x, y: x + "\n" + y

# Get the name of the atlas, which is the last folder of the directory.
def _get_atlas_name(A):
    direc = A.directory
    b = direc.rindex("/")
    if "/" in direc[:b]:
        a = direc[:b].rindex("/")
    else:
        a = -1
    return direc[a + 1:b]

# The preamble to the tex document containing all the stuff above 
# "\begin{document}."
def _preamble(title="", author=""):
    lines = [
        "\\documentclass[a4paper]{article}\n",
        "\\usepackage{enumerate}",
        "\\usepackage{hyperref}",
        "\\hypersetup{",
        "\tcolorlinks=true,",
        "\tlinkcolor=blue,",
        "\tfilecolor=blue,",
        "\turlcolor=blue,",
        "\tcitecolor=blue,",
        "}",
        "\\usepackage{amsmath}",
        "\\usepackage{amsthm}",
        "\\usepackage{amssymb}",
        "\\usepackage[margin=2cm]{geometry}",
        "\\usepackage{mathpazo}",
        "\\usepackage{url}",
        "\\usepackage[labelformat=simple]{subcaption}",
        "\\usepackage{tikz}",
        "\\usepackage{pgf}",
        "\\usepackage{longtable}",
        "\\usepackage{multirow}",
        "\\usepackage{graphicx}\n",
        "\\allowdisplaybreaks\n",
        "\\title{%s}" % (title),
        "\\author{%s}" % (author),
        "\\date{\\today}"
    ]
    return reduce(_cat_with_space, lines)
    
# The introduction of the tex document. 
def _intro(direc):
    sing_zeta = "\\textsf{SingularZeta}"
    direc_str = "\\texttt{%s}" % (direc)
    Fp = "$\\mathbb{F}_p$"
    intro = """
        This is a report generated by %s concerning the chart data in the 
        directory %s. We report all the computations we undertake in computing 
        the cone integral associated to %s. While this report is being 
        developed, we provide the table of varieties for which we need to count 
        the number of %s-rational points. The rows with no entry under %s-points
        cannot be done automatically with the current implementation of %s. 
        Special attention should be given to the ones with no %s-points if such 
        examples arise. 
    """ % (
        sing_zeta, 
        direc_str,
        direc_str,
        Fp, 
        Fp,
        sing_zeta,
        Fp
    )
    return intro.replace("        ", "")

# The introduction of the tex document. 
def _intro_integral(direc):
    sing_zeta = "\\textsf{SingularZeta}"
    direc_str = "\\texttt{%s}" % (direc)
    intro = """
        This is a report generated by %s concerning the integral data in the 
        directory %s. We report all the computations we undertake in computing 
        the cone integral associated to %s. This report should be read as a kind
        of ``printout.'' We write down all of the details as if solving this by
        hand. We start with the main integral, and then we move to the charts
        that correspond to leaves in the blow-up tree of %s. From each of these
        charts, we traverse the vertices of the intersection poset of the
        divisors. For each vertex, we write down the simplified integral. The
        goal is that all of these integrals are written down correctly and are
        monomial. 
    """ % (
        sing_zeta, 
        direc_str,
        direc_str,
        direc_str
    )
    return intro.replace("        ", "")

# Given a set of integers, return a latex compatible string for a set of 
# integers.
def _set_to_latex(S):
    content = reduce(lambda x, y: x + str(y) + ", ", S, "")
    return "$\\{" + content[:-2] + "\\}$"

# Format a polynomial to a latex compatible string.
def _format_poly(f):
    from sage.all import latex
    return "$%s$" % (latex(f))

# Convert the dictionary output by pRationalPorints into latex output.
def _poly_data_to_latex(P):
    from sage.all import latex
    system = P["simplified_system"]
    gens = P["simplified_ring"].gens()
    def _format_system(S):
        sys_str = map(lambda f: latex(f), S)
        poly_sys = reduce(lambda x, y: x + y + ",\\; ", sys_str, "$")
        return poly_sys[:-4] + "$"
    if len(system) <= 1:
        return _format_poly(system[0]), len(gens)
    else:
        return _format_system(system), len(gens)

# A function that returns the header for the F_p table of non-polynomial point 
# counts.
def _Fp_nonpoly_header(exists=False):
    Fp = "$\\mathbb{F}_p$"
    sing_zeta = "\\textsf{SingularZeta}"
    header = """
        \\subsection{Varieties with non-polynomial %s-point counts}\n
    """ % (Fp)
    header.replace("        ", "")
    if exists:
        header += """
            We separate the table of varieties with %s-point count not obviously given by a polynomial. It is possible these varieties are given by a (uniform) polynomial, but %s could not guess this. 
        """ % (Fp, sing_zeta)
    else:
        header += """
            We guess that all varieties have an %s-point count that is given by a (uniform) polynomial, so we do not have a table for this section.
        """ % (Fp)
    return header.replace("            ", "")

# A function that returns the header for the F_p table concerning the guesses.
def _Fp_guess_header(exists=False):
    Fp = "$\\mathbb{F}_p$"
    header = """
        \\subsection{Varieties with estimated %s-point counts}\n
    """ % (Fp)
    header.replace("        ", "")
    if exists:
        header += """
            We include the table of varieties which we could not explicitly determine the polynomials for the number of %s-points. However, we explicitly computed the counts for an overfit set of primes, so we expect these polynomials to be correct for all but finitely many primes.
        """ % (Fp)
    else:
        header += """
            We were not able to guess any of the %s-point counts for the varieties in this atlas. 
        """ % (Fp)
    return header.replace("            ", "")

# A function that returns the header for the entire F_p table.
def _Fp_table_header():
    Fp = "$\\mathbb{F}_p$"
    header = """
        \\subsection{The %s-point counts for all varieties}

        We write all the varieties for all the monomial cone integrals in one 
        table. 
    """ % (Fp)
    return header.replace("        ", "")

# A function that returns the header for the entire F_p table.
def _unique_Fp_table_header():
    Fp = "$\\mathbb{F}_p$"
    header = """
        \\subsection{The unique %s-point counts for all varieties}

        By unique points, we mean the points only contained in a variety and,
        thus, not contained in any other variety. We write all the varieties 
        for all the monomial cone integrals in
        one table. 
    """ % (Fp)
    return header.replace("        ", "")

# A function to build the F_p-table of the varieties with non-polynomial 
# Fp-point counts as a latex compatible string.
def _build_nonpoly_Fp_table(chrts):
    table_top = [
        "\\begin{center}",
        "\t\\begin{longtable}{|c|c|p{6cm}|c|c|}",
        "\t\t\\hline",
        "\t\t\\textbf{Chart} & " +
            "\\textbf{Vertex} & " + 
            "\\textbf{Variety} & " + 
            "\\textbf{Dim.}\\\\ \\hline \\hline" 
    ]
    table_end = [
        "\t\\end{longtable}",
        "\\end{center}"
    ]

    # The main function we apply to all charts.
    def extraction(C):
        ID = C._id
        V = C.intLat.vertices
        Fp = C.intLat.pRationalPoints()
        data = zip(V, Fp)

        def get_info(X):
            info = "\t\t%s & %s & " % (ID, _set_to_latex(X[0]))
            info += "%s & %s" % (_poly_data_to_latex(X[1][1]))
            if not "C" in str(X[1][0]):
                return ""
            info += " \\\\ \\hline"
            return info

        chart_section = filter(lambda l: l != "", map(get_info, data))
        if len(chart_section) == 0: 
            return [""]
        chart_section[-1] = chart_section[-1] + " \\hline"
        return chart_section

    # Get all the chart data from extraction, and flatten it down.
    table_main = reduce(lambda x, y: x + y, map(extraction, chrts), [])
    table = table_top + table_main + table_end
    return reduce(_cat_with_space, table)

# A function to build the F_p-table of the varieties where we guessed the 
# Fp-point count with polynomials. 
def _build_estimate_Fp_table(chrts):
    table_top = [
        "\\begin{center}",
        "\t\\begin{longtable}{|c|c|p{6cm}|c|c|c|}",
        "\t\t\\hline",
        "\t\t\\textbf{Chart} & " +
            "\\textbf{Vertex} & " + 
            "\\textbf{Variety} & " + 
            "\\textbf{Dim.} & " + 
            "\\textbf{Guess}\\\\ \\hline \\hline" 
    ]
    table_end = [
        "\t\\end{longtable}",
        "\\end{center}"
    ]

    # The main function we apply to all charts.
    def extraction(C):
        ID = C._id
        V = C.intLat.vertices
        Fp = C.intLat.pRationalPoints()
        data = zip(V, Fp)

        def get_info(X):
            info = "\t\t%s & %s & " % (ID, _set_to_latex(X[0]))
            info += "%s & %s & " % (_poly_data_to_latex(X[1][1]))
            if "X" in str(X[1][0]):
                info += "{\\footnotesize " + _format_poly(X[1][0]) + "}"
            else: 
                return ""
            info += " \\\\ \\hline"
            return info

        chart_section = filter(lambda l: l != "", map(get_info, data))
        if len(chart_section) == 0: 
            return [""]
        chart_section[-1] = chart_section[-1] + " \\hline"
        return chart_section

    # Get all the chart data from extraction, and flatten it down.
    table_main = reduce(lambda x, y: x + y, map(extraction, chrts), [])
    table = table_top + table_main + table_end
    return reduce(_cat_with_space, table)

# A function to build the entire F_p-table as a latex compatible string.
def _build_Fp_table(A):
    Fp = "$\\mathbb{F}_p$"
    table_top = [
        "\\begin{center}",
        "\t\\begin{longtable}{|c|c|p{6cm}|c|c|c|}",
        "\t\t\\hline",
        "\t\t\\textbf{Chart} & " +
            "\\textbf{Vertex} & " + 
            "\\textbf{Variety} & " + 
            "\\textbf{Dim.}\\ & " + 
            "%s-\\textbf{points}\\\\ \\hline \\hline" % (Fp)
    ]
    table_end = [
        "\t\\end{longtable}",
        "\\end{center}"
    ]

    # The main function we apply to all charts.
    def extraction(C):
        ID = C._id
        V = C.intLat.vertices
        Fp = C.intLat.pRationalPoints()
        data = zip(V, Fp)

        def get_info(X):
            info = "\t\t%s & %s & " % (ID, _set_to_latex(X[0]))
            info += "%s & %s & " % (_poly_data_to_latex(X[1][1]))
            if not "C" in str(X[1][0]):
                info += "{\\footnotesize " + _format_poly(X[1][0]) + "}"
            else: 
                # is_poly, f = _guess_polynomial(X[1][1]["simplified_ring"], X[1][1]["simplified_system"])
                # if is_poly:
                #     info += "{\\footnotesize " + _format_poly(f) + "}"
                # else:
                info += "{\\tiny NOT POLYNOMIAL}"
            info += " \\\\ \\hline"
            return info

        chart_section = map(get_info, data)
        chart_section[-1] = chart_section[-1] + " \\hline"
        return chart_section

    # Get all the chart data from extraction, and flatten it down.
    table_main = reduce(lambda x, y: x + y, map(extraction, A.charts), [])
    # Put everything together and return a string.
    table = table_top + table_main + table_end
    return reduce(_cat_with_space, table)


# A function to build the entire unique F_p-table as a latex compatible string.
def _build_unique_Fp_table(A):
    Fp = "$\\mathbb{F}_p$"
    table_top = [
        "\\begin{center}",
        "\t\\begin{longtable}{|c|c|p{6cm}|c|c|c|}",
        "\t\t\\hline",
        "\t\t\\textbf{Chart} & " +
            "\\textbf{Vertex} & " + 
            "\\textbf{Variety} & " + 
            "\\textbf{Dim.}\\ & " + 
            "%s-\\textbf{points}\\\\ \\hline \\hline" % (Fp)
    ]
    table_end = [
        "\t\\end{longtable}",
        "\\end{center}"
    ]

    # The main function we apply to all charts.
    def extraction(C):
        ID = C._id
        V = C.intLat.vertices
        Fp = C.intLat.pRationalPoints()
        Fp = list(map(lambda x: list(x), Fp))
        for i in range(len(Fp)):
            Fp[i][0] = C.intLat._vertexToPoints[i]
        data = zip(V, Fp)

        def get_info(X):
            info = "\t\t%s & %s & " % (ID, _set_to_latex(X[0]))
            info += "%s & %s & " % (_poly_data_to_latex(X[1][1]))
            if not "C" in str(X[1][0]):
                info += "{\\footnotesize " + _format_poly(X[1][0]) + "}"
            else: 
                # is_poly, f = _guess_polynomial(X[1][1]["simplified_ring"], X[1][1]["simplified_system"])
                # if is_poly:
                #     info += "{\\footnotesize " + _format_poly(f) + "}"
                # else:
                info += "{\\tiny NOT POLYNOMIAL}"
            info += " \\\\ \\hline"
            return info

        chart_section = map(get_info, data)
        chart_section[-1] = chart_section[-1] + " \\hline"
        return chart_section

    # Get all the chart data from extraction, and flatten it down.
    table_main = reduce(lambda x, y: x + y, map(extraction, A.charts), [])
    # Put everything together and return a string.
    table = table_top + table_main + table_end
    return reduce(_cat_with_space, table)

def _cone_cond(C):
    from sage.all import latex 
    first = "\\begin{align*}\n"
    last = "\\end{align*}\n"
    def one_line(T):
        return "v_p(%s) &\leq v_p(%s) \\\\\n" % (latex(T[0]), latex(T[1]))
    lines = reduce(lambda x, y: x + y, map(one_line, C), "").replace("\\left", "").replace("\\right", "")
    return first + lines + last

def _main_int(A):
    from sage.all import latex, gens
    I = A.integrand 
    para = """
        The main integral we aim to solve is:
        \\begin{equation}
            %s \\int_{S} %s \,|\mathrm{d}X|,
        \\end{equation}
        where $S$ is the subset of $\\mathbb{Z}_p^{%s}$ such that 
        %s
    """ % (latex(I.pFactor().simplify()), I.InsideLatex(), len(gens(A.root.AmbientSpace())), _cone_cond(A.root.cone))
    def chart_to_verts(x): 
        try:
            return len(x.intLat.vertices)
        except: 
            return 0
    add_up = lambda x, y: x + y 
    Nverts = reduce(add_up, map(chart_to_verts, A.charts))
    next_para = """
        We use %s charts, %s of which are leaves. There are a total of %s
        integrals to solve. 
    """ % (A.number_of_charts, len(A.charts), Nverts)
    return (para + next_para).replace("        ", "")

def _birationalmap_data(O, N):
    from sage.all import latex 
    first_line = "\\begin{align*}\n"
    last_line = "\\end{align*}\n"
    V = list(zip(O, N))
    n = len(V) // 2 + len(V) % 2
    V1 = V[:n]
    V2 = V[n:]
    mid = ""
    for i in range(n):
        if i < len(V2):
            mid += "%s &\\mapsto %s & %s &\\mapsto %s %s \n" % (latex(V1[i][0]), latex(V1[i][1]), latex(V2[i][0]), latex(V2[i][1]), "\\\\"*(i != n - 1))
        else: 
            mid += "%s &\\mapsto %s & & \n" % (latex(V1[i][0]), latex(V1[i][1]))
    return first_line + mid + last_line

def _chart_data(C):
    from sage.all import latex 
    A = C.atlas 
    old_vars = A.root.birationalMap
    new_vars = C.birationalMap
    intro = "We apply the following substitution to the initial variables:\n"
    biratmap = _birationalmap_data(old_vars, new_vars)
    jac = "This substitution yields a Jacobian factor equal to \n\\begin{align*}\n\\left|%s\\right|.\n\\end{align*}\n" % (latex(C.jacDet))
    f = reduce(lambda x, y: x + y + ",", map(lambda z: latex(z), C.focus), "")
    focus = "The focus is generated by the following:\n\\begin{align*}\n%s.\n\\end{align*}\n" % (f[:-1])
    I = C.Integrand()
    integral = "The integral simplifies to \n\\begin{equation}\n%s \\int_{S} %s \,|\mathrm{d}X|,\n\\end{equation}\n" % (latex(I.pFactor().simplify()), I.InsideLatex())
    cone = "with cone conditions given by:\n" + _cone_cond(C.cone)
    return intro + biratmap + jac + focus + integral + cone 

def _subchart_section(C):
    from sage.all import latex
    Subs = C.Subcharts()
    P = C.intLat
    verts = P.vertices 
    prod = reduce(lambda x, y: x*y, P.divisors, 1)
    subs = ""
    for i in range(len(verts)):
        subs += "\n\\subsection{Vertex $%s$}\n\n" % (latex(verts[i]).replace("\\left", "").replace("\\right", ""))
        if len(verts[i]) < len(P.divisors):
            subs += "On this subchart, we assume the following divisors are units:\n"
            subs += "\\begin{align*}\n"
            subs += reduce(lambda x, y: x + y + " && ", map(lambda j: latex(P.divisors[j]), [j for j in range(len(P.divisors)) if not j in verts[i]]), "")[:-3] + ",\n" 
            subs += "\\end{align*}\n"
        else:
            subs += "None of the divisors are considered to be units, "
        subs += "and the following divisors are divisible by $p$:\n"
        subs += "\\begin{align*}\n"
        subs += reduce(lambda x, y: x + y + " && ", map(lambda j: latex(P.divisors[j]), verts[i]), "")[:-3] + ".\n" 
        subs += "\\end{align*}\n"
        if len(verts[i]) > 0:
            subs += "We make the following substitutions:\n\\begin{align*}\n"
            for j in range(len(verts[i])):
                subs += "%s &= pz_{%s}, &" % (latex(P.divisors[sorted(list(verts[i]))[j]]), j + 1)
            subs = subs[:-3] + ".\n\\end{align*}\n"
        subs += "The number of points in $\\mathbb{F}_p^{%d}$ contained in this subchart and no others is equal to\n$$\n%s.\n$$\n\n" % (len(prod.variables()), latex(P._vertexToPoints[i]))
        subs += _chart_data(Subs[i])
    return subs

def _chart_section(C, direc=""):
    from sage.all import latex 
    sect_title = "\\section{Chart %s}\n\n" % (C._id)
    if C.intLat:
        P = C.intLat
        if len(P.poset) > 0:
            P_plot = P.poset.plot()
            p_name = "img/Poset" + C._id + ".png"
            P_plot.save(direc + p_name)
            pos = "The intersection poset for this chart looks like\n\n\\begin{center}\n\\includegraphics[scale=0.5]{%s}\n\\end{center}\n" % (p_name)
            pos += "The vertices of the above poset are labeled by sets of integers. The integers correspond to the following divisors: \n\\begin{enumerate}\n"
            pos += reduce(lambda x, y: x + y, map(lambda d: "\\item[%s:] $%s$\n" % (P.divisors.index(d), latex(d)), P.divisors), "")
            pos += "\\end{enumerate}\n"
            if not P.poset.is_isomorphic(P.DivisorPoset()):
                p_name_new = "img/Poset" + C._id + "_new.png"
                P_plot_new = P.DivisorPoset().plot()
                P_plot_new.save(direc + p_name_new)
                pos += "\nThe above poset seems to be \\textbf{incorrect}. Using the same labels, the poset should be as follows\n\n\\begin{center}\n\\includegraphics[scale=0.5]{%s}\n\\end{center}\n" % (p_name_new)
            subs = _subchart_section(C)
        else: 
            pos = "The intersection poset is trivial since the integral is already monomial, and so there are no further subdivisions of this chart.\n"
            subs = ""
    else:
        pos = "This chart does not have any data for its intersection poset.\n"
        subs = ""
    return sect_title + _chart_data(C) + pos + subs

# ==============================================================================
#   Main function
# ==============================================================================

# The following is a function that outputs a tex file. The tex file provides 
# information concerning the polynomials associated to the atlas A for which we 
# cannot automatically determine the number of F_p-rational points. 
def RationalReport(A, file=""): 
    # Take care of input
    if not isinstance(file, str):
        raise TypeError("Expected 'file' to be a string.")

    # Make sure the file string is formatted correctly.
    atlas_name = _get_atlas_name(A)
    if file == "":
        file = atlas_name + "_RationalReport.tex"
    if not ".tex" in file:
        file_name = file + ".tex"
    else:
        file_name = file
    atlas_name_latex = atlas_name.replace("_", "\\_")

    title = "Rational report for %s" % (atlas_name_latex)
    with open(file_name, 'w') as tex_file:
        tex_file.write(_preamble(title=title))
        tex_file.write("\n\n\\begin{document}")
        tex_file.write("\n\n\\maketitle")
        tex_file.write("\n\\tableofcontents\n\n")
        tex_file.write("\n\n\\section{Introduction}\n\n")
        tex_file.write(_intro(atlas_name_latex))
    
    with open(file_name, 'a') as tex_file:
        tex_file.write("\n\n\\section{Counting $\\mathbb{F}_p$-points}")

    # Determine the F_p-rational points of the atlas. 
    # These are stored with the intersection lattices.
    # If these were previously computed, then nothing happens here.
    _ = map(lambda C: C.intLat.pRationalPoints(user_input=False), A.charts)

    # Get the charts with a vertex with non-polynomial point count. 
    def nonpoly(C):
        Fp_counts = C.intLat.pRationalPoints()
        counts = list(map(lambda X: X[0], Fp_counts))
        return filter(lambda x: "C" in str(x), counts) != []
    nonpoly_chrts = list(filter(nonpoly, A.charts))

    if _verbose >= 1:
        print("Guessing polynomial Fp-point counts.")

    nonpoly_exists = False
    guess_exists = False
    # A function we apply to the nonpoly charts. If it guesses a poly it will 
    # replace the non-guess with a polynomial in X.
    def guess_chart(C): 
        Fp_points = C.intLat.pRationalPoints()
        def guess_func(data):
            if "C" in str(data[0]):
                is_poly, f = _guess_polynomial(data[1]["simplified_ring"], 
                data[1]["simplified_system"])
                if is_poly:
                    guess_exists = True
                    return tuple([f, data[1]])
                nonpoly_exists = True
            return data
        C.intLat.p_points = map(guess_func, Fp_points)
        return C
    checked_chrts = map(guess_chart, nonpoly_chrts)

    # Build the non-polynomial table
    nonpoly_table = _build_nonpoly_Fp_table(checked_chrts)
    # Build the estimate table 
    estimate_table = _build_estimate_Fp_table(checked_chrts)
    # Build the entire table
    table = _build_Fp_table(A)
    # Build the entire unique table
    unique_table = _build_unique_Fp_table(A)

    with open(file_name, 'a') as tex_file:
        tex_file.write("\n\n" + _Fp_nonpoly_header(exists=nonpoly_exists))
        tex_file.write("\n\n" + nonpoly_table + "\n\n")
        tex_file.write("\n\n" + _Fp_guess_header(exists=guess_exists))
        tex_file.write("\n\n" + estimate_table + "\n\n")
        tex_file.write("\n\n" + _Fp_table_header())
        tex_file.write("\n\n" + table + "\n\n")
        tex_file.write("\n\n" + _unique_Fp_table_header())
        tex_file.write("\n\n" + unique_table + "\n\n")

    with open(file_name, 'a') as tex_file:
        tex_file.write("\n\n\\end{document}")

    return 

# The following is a function that outputs a tex file. The tex file provides 
# information concerning the integrals associated to the atlas A.
def IntegralReport(A, direc=""):
    # Make sure the file string is formatted correctly.
    atlas_name = _get_atlas_name(A)
    file_name = direc + atlas_name + "_IntReport.tex"
    atlas_name_latex = atlas_name.replace("_", "\\_")

    title = "Integral report for %s" % (atlas_name_latex)
    with open(file_name, 'w') as tex_file:
        tex_file.write(_preamble(title=title))
        tex_file.write("\n\n\\begin{document}")
        tex_file.write("\n\n\\maketitle")
        tex_file.write("\n\\tableofcontents\n\n")
        tex_file.write("\n\n\\section{Introduction}\n\n")
        tex_file.write(_intro_integral(atlas_name_latex))
    
    with open(file_name, 'a') as tex_file:
        tex_file.write("\n\n\\section{Main integral}\n\n")
        tex_file.write(_main_int(A))

    with open(file_name, 'a') as tex_file:
        for C in A.charts:
            tex_file.write(_chart_section(C, direc=direc))

    with open(file_name, 'a') as tex_file:
        tex_file.write("\n\n\\end{document}")

    return 
#
#   Copyright 2020 <NAME> 
#
#   Distributed under MIT License
#


from rationalPoints import _guess_polynomial
from globalVars import _DEFAULT_VERBOSE as _verbose

# A useful function for multiple lines
_cat_with_space = lambda x, y: x + "\n" + y

# Get the name of the atlas, which is the last folder of the directory.
def _get_atlas_name(A):
    direc = A.directory
    b = direc.rindex("/")
    if "/" in direc[:b]:
        a = direc[:b].rindex("/")
    else:
        a = -1
    return direc[a + 1:b]

# The preamble to the tex document containing all the stuff above 
# "\begin{document}."
def _preamble(title="", author=""):
    lines = [
        "\\documentclass[a4paper]{article}\n",
        "\\usepackage{enumerate}",
        "\\usepackage{hyperref}",
        "\\hypersetup{",
        "\tcolorlinks=true,",
        "\tlinkcolor=blue,",
        "\tfilecolor=blue,",
        "\turlcolor=blue,",
        "\tcitecolor=blue,",
        "}",
        "\\usepackage{amsmath}",
        "\\usepackage{amsthm}",
        "\\usepackage{amssymb}",
        "\\usepackage[margin=2cm]{geometry}",
        "\\usepackage{mathpazo}",
        "\\usepackage{url}",
        "\\usepackage[labelformat=simple]{subcaption}",
        "\\usepackage{tikz}",
        "\\usepackage{pgf}",
        "\\usepackage{longtable}",
        "\\usepackage{multirow}",
        "\\usepackage{graphicx}\n",
        "\\allowdisplaybreaks\n",
        "\\title{%s}" % (title),
        "\\author{%s}" % (author),
        "\\date{\\today}"
    ]
    return reduce(_cat_with_space, lines)
    
# The introduction of the tex document. 
def _intro(direc):
    sing_zeta = "\\textsf{SingularZeta}"
    direc_str = "\\texttt{%s}" % (direc)
    Fp = "$\\mathbb{F}_p$"
    intro = """
        This is a report generated by %s concerning the chart data in the 
        directory %s. We report all the computations we undertake in computing 
        the cone integral associated to %s. While this report is being 
        developed, we provide the table of varieties for which we need to count 
        the number of %s-rational points. The rows with no entry under %s-points
        cannot be done automatically with the current implementation of %s. 
        Special attention should be given to the ones with no %s-points if such 
        examples arise. 
    """ % (
        sing_zeta, 
        direc_str,
        direc_str,
        Fp, 
        Fp,
        sing_zeta,
        Fp
    )
    return intro.replace("        ", "")

# The introduction of the tex document. 
def _intro_integral(direc):
    sing_zeta = "\\textsf{SingularZeta}"
    direc_str = "\\texttt{%s}" % (direc)
    intro = """
        This is a report generated by %s concerning the integral data in the 
        directory %s. We report all the computations we undertake in computing 
        the cone integral associated to %s. This report should be read as a kind
        of ``printout.'' We write down all of the details as if solving this by
        hand. We start with the main integral, and then we move to the charts
        that correspond to leaves in the blow-up tree of %s. From each of these
        charts, we traverse the vertices of the intersection poset of the
        divisors. For each vertex, we write down the simplified integral. The
        goal is that all of these integrals are written down correctly and are
        monomial. 
    """ % (
        sing_zeta, 
        direc_str,
        direc_str,
        direc_str
    )
    return intro.replace("        ", "")

# Given a set of integers, return a latex compatible string for a set of 
# integers.
def _set_to_latex(S):
    content = reduce(lambda x, y: x + str(y) + ", ", S, "")
    return "$\\{" + content[:-2] + "\\}$"

# Format a polynomial to a latex compatible string.
def _format_poly(f):
    from sage.all import latex
    return "$%s$" % (latex(f))

# Convert the dictionary output by pRationalPorints into latex output.
def _poly_data_to_latex(P):
    from sage.all import latex
    system = P["simplified_system"]
    gens = P["simplified_ring"].gens()
    def _format_system(S):
        sys_str = map(lambda f: latex(f), S)
        poly_sys = reduce(lambda x, y: x + y + ",\\; ", sys_str, "$")
        return poly_sys[:-4] + "$"
    if len(system) <= 1:
        return _format_poly(system[0]), len(gens)
    else:
        return _format_system(system), len(gens)

# A function that returns the header for the F_p table of non-polynomial point 
# counts.
def _Fp_nonpoly_header(exists=False):
    Fp = "$\\mathbb{F}_p$"
    sing_zeta = "\\textsf{SingularZeta}"
    header = """
        \\subsection{Varieties with non-polynomial %s-point counts}\n
    """ % (Fp)
    header.replace("        ", "")
    if exists:
        header += """
            We separate the table of varieties with %s-point count not obviously given by a polynomial. It is possible these varieties are given by a (uniform) polynomial, but %s could not guess this. 
        """ % (Fp, sing_zeta)
    else:
        header += """
            We guess that all varieties have an %s-point count that is given by a (uniform) polynomial, so we do not have a table for this section.
        """ % (Fp)
    return header.replace("            ", "")

# A function that returns the header for the F_p table concerning the guesses.
def _Fp_guess_header(exists=False):
    Fp = "$\\mathbb{F}_p$"
    header = """
        \\subsection{Varieties with estimated %s-point counts}\n
    """ % (Fp)
    header.replace("        ", "")
    if exists:
        header += """
            We include the table of varieties which we could not explicitly determine the polynomials for the number of %s-points. However, we explicitly computed the counts for an overfit set of primes, so we expect these polynomials to be correct for all but finitely many primes.
        """ % (Fp)
    else:
        header += """
            We were not able to guess any of the %s-point counts for the varieties in this atlas. 
        """ % (Fp)
    return header.replace("            ", "")

# A function that returns the header for the entire F_p table.
def _Fp_table_header():
    Fp = "$\\mathbb{F}_p$"
    header = """
        \\subsection{The %s-point counts for all varieties}

        We write all the varieties for all the monomial cone integrals in one 
        table. 
    """ % (Fp)
    return header.replace("        ", "")

# A function that returns the header for the entire F_p table.
def _unique_Fp_table_header():
    Fp = "$\\mathbb{F}_p$"
    header = """
        \\subsection{The unique %s-point counts for all varieties}

        By unique points, we mean the points only contained in a variety and,
        thus, not contained in any other variety. We write all the varieties 
        for all the monomial cone integrals in
        one table. 
    """ % (Fp)
    return header.replace("        ", "")

# A function to build the F_p-table of the varieties with non-polynomial 
# Fp-point counts as a latex compatible string.
def _build_nonpoly_Fp_table(chrts):
    table_top = [
        "\\begin{center}",
        "\t\\begin{longtable}{|c|c|p{6cm}|c|c|}",
        "\t\t\\hline",
        "\t\t\\textbf{Chart} & " +
            "\\textbf{Vertex} & " + 
            "\\textbf{Variety} & " + 
            "\\textbf{Dim.}\\\\ \\hline \\hline" 
    ]
    table_end = [
        "\t\\end{longtable}",
        "\\end{center}"
    ]

    # The main function we apply to all charts.
    def extraction(C):
        ID = C._id
        V = C.intLat.vertices
        Fp = C.intLat.pRationalPoints()
        data = zip(V, Fp)

        def get_info(X):
            info = "\t\t%s & %s & " % (ID, _set_to_latex(X[0]))
            info += "%s & %s" % (_poly_data_to_latex(X[1][1]))
            if not "C" in str(X[1][0]):
                return ""
            info += " \\\\ \\hline"
            return info

        chart_section = filter(lambda l: l != "", map(get_info, data))
        if len(chart_section) == 0: 
            return [""]
        chart_section[-1] = chart_section[-1] + " \\hline"
        return chart_section

    # Get all the chart data from extraction, and flatten it down.
    table_main = reduce(lambda x, y: x + y, map(extraction, chrts), [])
    table = table_top + table_main + table_end
    return reduce(_cat_with_space, table)

# A function to build the F_p-table of the varieties where we guessed the 
# Fp-point count with polynomials. 
def _build_estimate_Fp_table(chrts):
    table_top = [
        "\\begin{center}",
        "\t\\begin{longtable}{|c|c|p{6cm}|c|c|c|}",
        "\t\t\\hline",
        "\t\t\\textbf{Chart} & " +
            "\\textbf{Vertex} & " + 
            "\\textbf{Variety} & " + 
            "\\textbf{Dim.} & " + 
            "\\textbf{Guess}\\\\ \\hline \\hline" 
    ]
    table_end = [
        "\t\\end{longtable}",
        "\\end{center}"
    ]

    # The main function we apply to all charts.
    def extraction(C):
        ID = C._id
        V = C.intLat.vertices
        Fp = C.intLat.pRationalPoints()
        data = zip(V, Fp)

        def get_info(X):
            info = "\t\t%s & %s & " % (ID, _set_to_latex(X[0]))
            info += "%s & %s & " % (_poly_data_to_latex(X[1][1]))
            if "X" in str(X[1][0]):
                info += "{\\footnotesize " + _format_poly(X[1][0]) + "}"
            else: 
                return ""
            info += " \\\\ \\hline"
            return info

        chart_section = filter(lambda l: l != "", map(get_info, data))
        if len(chart_section) == 0: 
            return [""]
        chart_section[-1] = chart_section[-1] + " \\hline"
        return chart_section

    # Get all the chart data from extraction, and flatten it down.
    table_main = reduce(lambda x, y: x + y, map(extraction, chrts), [])
    table = table_top + table_main + table_end
    return reduce(_cat_with_space, table)

# A function to build the entire F_p-table as a latex compatible string.
def _build_Fp_table(A):
    Fp = "$\\mathbb{F}_p$"
    table_top = [
        "\\begin{center}",
        "\t\\begin{longtable}{|c|c|p{6cm}|c|c|c|}",
        "\t\t\\hline",
        "\t\t\\textbf{Chart} & " +
            "\\textbf{Vertex} & " + 
            "\\textbf{Variety} & " + 
            "\\textbf{Dim.}\\ & " + 
            "%s-\\textbf{points}\\\\ \\hline \\hline" % (Fp)
    ]
    table_end = [
        "\t\\end{longtable}",
        "\\end{center}"
    ]

    # The main function we apply to all charts.
    def extraction(C):
        ID = C._id
        V = C.intLat.vertices
        Fp = C.intLat.pRationalPoints()
        data = zip(V, Fp)

        def get_info(X):
            info = "\t\t%s & %s & " % (ID, _set_to_latex(X[0]))
            info += "%s & %s & " % (_poly_data_to_latex(X[1][1]))
            if not "C" in str(X[1][0]):
                info += "{\\footnotesize " + _format_poly(X[1][0]) + "}"
            else: 
                # is_poly, f = _guess_polynomial(X[1][1]["simplified_ring"], X[1][1]["simplified_system"])
                # if is_poly:
                #     info += "{\\footnotesize " + _format_poly(f) + "}"
                # else:
                info += "{\\tiny NOT POLYNOMIAL}"
            info += " \\\\ \\hline"
            return info

        chart_section = map(get_info, data)
        chart_section[-1] = chart_section[-1] + " \\hline"
        return chart_section

    # Get all the chart data from extraction, and flatten it down.
    table_main = reduce(lambda x, y: x + y, map(extraction, A.charts), [])
    # Put everything together and return a string.
    table = table_top + table_main + table_end
    return reduce(_cat_with_space, table)


# A function to build the entire unique F_p-table as a latex compatible string.
def _build_unique_Fp_table(A):
    Fp = "$\\mathbb{F}_p$"
    table_top = [
        "\\begin{center}",
        "\t\\begin{longtable}{|c|c|p{6cm}|c|c|c|}",
        "\t\t\\hline",
        "\t\t\\textbf{Chart} & " +
            "\\textbf{Vertex} & " + 
            "\\textbf{Variety} & " + 
            "\\textbf{Dim.}\\ & " + 
            "%s-\\textbf{points}\\\\ \\hline \\hline" % (Fp)
    ]
    table_end = [
        "\t\\end{longtable}",
        "\\end{center}"
    ]

    # The main function we apply to all charts.
    def extraction(C):
        ID = C._id
        V = C.intLat.vertices
        Fp = C.intLat.pRationalPoints()
        Fp = list(map(lambda x: list(x), Fp))
        for i in range(len(Fp)):
            Fp[i][0] = C.intLat._vertexToPoints[i]
        data = zip(V, Fp)

        def get_info(X):
            info = "\t\t%s & %s & " % (ID, _set_to_latex(X[0]))
            info += "%s & %s & " % (_poly_data_to_latex(X[1][1]))
            if not "C" in str(X[1][0]):
                info += "{\\footnotesize " + _format_poly(X[1][0]) + "}"
            else: 
                # is_poly, f = _guess_polynomial(X[1][1]["simplified_ring"], X[1][1]["simplified_system"])
                # if is_poly:
                #     info += "{\\footnotesize " + _format_poly(f) + "}"
                # else:
                info += "{\\tiny NOT POLYNOMIAL}"
            info += " \\\\ \\hline"
            return info

        chart_section = map(get_info, data)
        chart_section[-1] = chart_section[-1] + " \\hline"
        return chart_section

    # Get all the chart data from extraction, and flatten it down.
    table_main = reduce(lambda x, y: x + y, map(extraction, A.charts), [])
    # Put everything together and return a string.
    table = table_top + table_main + table_end
    return reduce(_cat_with_space, table)

def _cone_cond(C):
    from sage.all import latex 
    first = "\\begin{align*}\n"
    last = "\\end{align*}\n"
    def one_line(T):
        return "v_p(%s) &\leq v_p(%s) \\\\\n" % (latex(T[0]), latex(T[1]))
    lines = reduce(lambda x, y: x + y, map(one_line, C), "").replace("\\left", "").replace("\\right", "")
    return first + lines + last

def _main_int(A):
    from sage.all import latex, gens
    I = A.integrand 
    para = """
        The main integral we aim to solve is:
        \\begin{equation}
            %s \\int_{S} %s \,|\mathrm{d}X|,
        \\end{equation}
        where $S$ is the subset of $\\mathbb{Z}_p^{%s}$ such that 
        %s
    """ % (latex(I.pFactor().simplify()), I.InsideLatex(), len(gens(A.root.AmbientSpace())), _cone_cond(A.root.cone))
    def chart_to_verts(x): 
        try:
            return len(x.intLat.vertices)
        except: 
            return 0
    add_up = lambda x, y: x + y 
    Nverts = reduce(add_up, map(chart_to_verts, A.charts))
    next_para = """
        We use %s charts, %s of which are leaves. There are a total of %s
        integrals to solve. 
    """ % (A.number_of_charts, len(A.charts), Nverts)
    return (para + next_para).replace("        ", "")

def _birationalmap_data(O, N):
    from sage.all import latex 
    first_line = "\\begin{align*}\n"
    last_line = "\\end{align*}\n"
    V = list(zip(O, N))
    n = len(V) // 2 + len(V) % 2
    V1 = V[:n]
    V2 = V[n:]
    mid = ""
    for i in range(n):
        if i < len(V2):
            mid += "%s &\\mapsto %s & %s &\\mapsto %s %s \n" % (latex(V1[i][0]), latex(V1[i][1]), latex(V2[i][0]), latex(V2[i][1]), "\\\\"*(i != n - 1))
        else: 
            mid += "%s &\\mapsto %s & & \n" % (latex(V1[i][0]), latex(V1[i][1]))
    return first_line + mid + last_line

def _chart_data(C):
    from sage.all import latex 
    A = C.atlas 
    old_vars = A.root.birationalMap
    new_vars = C.birationalMap
    intro = "We apply the following substitution to the initial variables:\n"
    biratmap = _birationalmap_data(old_vars, new_vars)
    jac = "This substitution yields a Jacobian factor equal to \n\\begin{align*}\n\\left|%s\\right|.\n\\end{align*}\n" % (latex(C.jacDet))
    f = reduce(lambda x, y: x + y + ",", map(lambda z: latex(z), C.focus), "")
    focus = "The focus is generated by the following:\n\\begin{align*}\n%s.\n\\end{align*}\n" % (f[:-1])
    I = C.Integrand()
    integral = "The integral simplifies to \n\\begin{equation}\n%s \\int_{S} %s \,|\mathrm{d}X|,\n\\end{equation}\n" % (latex(I.pFactor().simplify()), I.InsideLatex())
    cone = "with cone conditions given by:\n" + _cone_cond(C.cone)
    return intro + biratmap + jac + focus + integral + cone 

def _subchart_section(C):
    from sage.all import latex
    Subs = C.Subcharts()
    P = C.intLat
    verts = P.vertices 
    prod = reduce(lambda x, y: x*y, P.divisors, 1)
    subs = ""
    for i in range(len(verts)):
        subs += "\n\\subsection{Vertex $%s$}\n\n" % (latex(verts[i]).replace("\\left", "").replace("\\right", ""))
        if len(verts[i]) < len(P.divisors):
            subs += "On this subchart, we assume the following divisors are units:\n"
            subs += "\\begin{align*}\n"
            subs += reduce(lambda x, y: x + y + " && ", map(lambda j: latex(P.divisors[j]), [j for j in range(len(P.divisors)) if not j in verts[i]]), "")[:-3] + ",\n" 
            subs += "\\end{align*}\n"
        else:
            subs += "None of the divisors are considered to be units, "
        subs += "and the following divisors are divisible by $p$:\n"
        subs += "\\begin{align*}\n"
        subs += reduce(lambda x, y: x + y + " && ", map(lambda j: latex(P.divisors[j]), verts[i]), "")[:-3] + ".\n" 
        subs += "\\end{align*}\n"
        if len(verts[i]) > 0:
            subs += "We make the following substitutions:\n\\begin{align*}\n"
            for j in range(len(verts[i])):
                subs += "%s &= pz_{%s}, &" % (latex(P.divisors[sorted(list(verts[i]))[j]]), j + 1)
            subs = subs[:-3] + ".\n\\end{align*}\n"
        subs += "The number of points in $\\mathbb{F}_p^{%d}$ contained in this subchart and no others is equal to\n$$\n%s.\n$$\n\n" % (len(prod.variables()), latex(P._vertexToPoints[i]))
        subs += _chart_data(Subs[i])
    return subs

def _chart_section(C, direc=""):
    from sage.all import latex 
    sect_title = "\\section{Chart %s}\n\n" % (C._id)
    if C.intLat:
        P = C.intLat
        if len(P.poset) > 0:
            P_plot = P.poset.plot()
            p_name = "img/Poset" + C._id + ".png"
            P_plot.save(direc + p_name)
            pos = "The intersection poset for this chart looks like\n\n\\begin{center}\n\\includegraphics[scale=0.5]{%s}\n\\end{center}\n" % (p_name)
            pos += "The vertices of the above poset are labeled by sets of integers. The integers correspond to the following divisors: \n\\begin{enumerate}\n"
            pos += reduce(lambda x, y: x + y, map(lambda d: "\\item[%s:] $%s$\n" % (P.divisors.index(d), latex(d)), P.divisors), "")
            pos += "\\end{enumerate}\n"
            if not P.poset.is_isomorphic(P.DivisorPoset()):
                p_name_new = "img/Poset" + C._id + "_new.png"
                P_plot_new = P.DivisorPoset().plot()
                P_plot_new.save(direc + p_name_new)
                pos += "\nThe above poset seems to be \\textbf{incorrect}. Using the same labels, the poset should be as follows\n\n\\begin{center}\n\\includegraphics[scale=0.5]{%s}\n\\end{center}\n" % (p_name_new)
            subs = _subchart_section(C)
        else: 
            pos = "The intersection poset is trivial since the integral is already monomial, and so there are no further subdivisions of this chart.\n"
            subs = ""
    else:
        pos = "This chart does not have any data for its intersection poset.\n"
        subs = ""
    return sect_title + _chart_data(C) + pos + subs

# ==============================================================================
#   Main function
# ==============================================================================

# The following is a function that outputs a tex file. The tex file provides 
# information concerning the polynomials associated to the atlas A for which we 
# cannot automatically determine the number of F_p-rational points. 
def RationalReport(A, file=""): 
    # Take care of input
    if not isinstance(file, str):
        raise TypeError("Expected 'file' to be a string.")

    # Make sure the file string is formatted correctly.
    atlas_name = _get_atlas_name(A)
    if file == "":
        file = atlas_name + "_RationalReport.tex"
    if not ".tex" in file:
        file_name = file + ".tex"
    else:
        file_name = file
    atlas_name_latex = atlas_name.replace("_", "\\_")

    title = "Rational report for %s" % (atlas_name_latex)
    with open(file_name, 'w') as tex_file:
        tex_file.write(_preamble(title=title))
        tex_file.write("\n\n\\begin{document}")
        tex_file.write("\n\n\\maketitle")
        tex_file.write("\n\\tableofcontents\n\n")
        tex_file.write("\n\n\\section{Introduction}\n\n")
        tex_file.write(_intro(atlas_name_latex))
    
    with open(file_name, 'a') as tex_file:
        tex_file.write("\n\n\\section{Counting $\\mathbb{F}_p$-points}")

    # Determine the F_p-rational points of the atlas. 
    # These are stored with the intersection lattices.
    # If these were previously computed, then nothing happens here.
    _ = map(lambda C: C.intLat.pRationalPoints(user_input=False), A.charts)

    # Get the charts with a vertex with non-polynomial point count. 
    def nonpoly(C):
        Fp_counts = C.intLat.pRationalPoints()
        counts = list(map(lambda X: X[0], Fp_counts))
        return filter(lambda x: "C" in str(x), counts) != []
    nonpoly_chrts = list(filter(nonpoly, A.charts))

    if _verbose >= 1:
        print("Guessing polynomial Fp-point counts.")

    nonpoly_exists = False
    guess_exists = False
    # A function we apply to the nonpoly charts. If it guesses a poly it will 
    # replace the non-guess with a polynomial in X.
    def guess_chart(C): 
        Fp_points = C.intLat.pRationalPoints()
        def guess_func(data):
            if "C" in str(data[0]):
                is_poly, f = _guess_polynomial(data[1]["simplified_ring"], 
                data[1]["simplified_system"])
                if is_poly:
                    guess_exists = True
                    return tuple([f, data[1]])
                nonpoly_exists = True
            return data
        C.intLat.p_points = map(guess_func, Fp_points)
        return C
    checked_chrts = map(guess_chart, nonpoly_chrts)

    # Build the non-polynomial table
    nonpoly_table = _build_nonpoly_Fp_table(checked_chrts)
    # Build the estimate table 
    estimate_table = _build_estimate_Fp_table(checked_chrts)
    # Build the entire table
    table = _build_Fp_table(A)
    # Build the entire unique table
    unique_table = _build_unique_Fp_table(A)

    with open(file_name, 'a') as tex_file:
        tex_file.write("\n\n" + _Fp_nonpoly_header(exists=nonpoly_exists))
        tex_file.write("\n\n" + nonpoly_table + "\n\n")
        tex_file.write("\n\n" + _Fp_guess_header(exists=guess_exists))
        tex_file.write("\n\n" + estimate_table + "\n\n")
        tex_file.write("\n\n" + _Fp_table_header())
        tex_file.write("\n\n" + table + "\n\n")
        tex_file.write("\n\n" + _unique_Fp_table_header())
        tex_file.write("\n\n" + unique_table + "\n\n")

    with open(file_name, 'a') as tex_file:
        tex_file.write("\n\n\\end{document}")

    return 

# The following is a function that outputs a tex file. The tex file provides 
# information concerning the integrals associated to the atlas A.
def IntegralReport(A, direc=""):
    # Make sure the file string is formatted correctly.
    atlas_name = _get_atlas_name(A)
    file_name = direc + atlas_name + "_IntReport.tex"
    atlas_name_latex = atlas_name.replace("_", "\\_")

    title = "Integral report for %s" % (atlas_name_latex)
    with open(file_name, 'w') as tex_file:
        tex_file.write(_preamble(title=title))
        tex_file.write("\n\n\\begin{document}")
        tex_file.write("\n\n\\maketitle")
        tex_file.write("\n\\tableofcontents\n\n")
        tex_file.write("\n\n\\section{Introduction}\n\n")
        tex_file.write(_intro_integral(atlas_name_latex))
    
    with open(file_name, 'a') as tex_file:
        tex_file.write("\n\n\\section{Main integral}\n\n")
        tex_file.write(_main_int(A))

    with open(file_name, 'a') as tex_file:
        for C in A.charts:
            tex_file.write(_chart_section(C, direc=direc))

    with open(file_name, 'a') as tex_file:
        tex_file.write("\n\n\\end{document}")

    return
# #   Copyright 2020 <NAME> # #   Distributed under MIT License # # A useful function for multiple lines # Get the name of the atlas, which is the last folder of the directory. # The preamble to the tex document containing all the stuff above # "\begin{document}." # The introduction of the tex document. This is a report generated by %s concerning the chart data in the          directory %s. We report all the computations we undertake in computing          the cone integral associated to %s. While this report is being          developed, we provide the table of varieties for which we need to count          the number of %s-rational points. The rows with no entry under %s-points         cannot be done automatically with the current implementation of %s.          Special attention should be given to the ones with no %s-points if such          examples arise. # The introduction of the tex document. This is a report generated by %s concerning the integral data in the          directory %s. We report all the computations we undertake in computing          the cone integral associated to %s. This report should be read as a kind         of ``printout.'' We write down all of the details as if solving this by         hand. We start with the main integral, and then we move to the charts         that correspond to leaves in the blow-up tree of %s. From each of these         charts, we traverse the vertices of the intersection poset of the         divisors. For each vertex, we write down the simplified integral. The         goal is that all of these integrals are written down correctly and are         monomial. # Given a set of integers, return a latex compatible string for a set of # integers. # Format a polynomial to a latex compatible string. # Convert the dictionary output by pRationalPorints into latex output. # A function that returns the header for the F_p table of non-polynomial point # counts. \\subsection{Varieties with non-polynomial %s-point counts}\n We separate the table of varieties with %s-point count not obviously given by a polynomial. It is possible these varieties are given by a (uniform) polynomial, but %s could not guess this. We guess that all varieties have an %s-point count that is given by a (uniform) polynomial, so we do not have a table for this section. # A function that returns the header for the F_p table concerning the guesses. \\subsection{Varieties with estimated %s-point counts}\n We include the table of varieties which we could not explicitly determine the polynomials for the number of %s-points. However, we explicitly computed the counts for an overfit set of primes, so we expect these polynomials to be correct for all but finitely many primes. We were not able to guess any of the %s-point counts for the varieties in this atlas. # A function that returns the header for the entire F_p table. \\subsection{The %s-point counts for all varieties}          We write all the varieties for all the monomial cone integrals in one          table. # A function that returns the header for the entire F_p table. \\subsection{The unique %s-point counts for all varieties}          By unique points, we mean the points only contained in a variety and,         thus, not contained in any other variety. We write all the varieties          for all the monomial cone integrals in         one table. # A function to build the F_p-table of the varieties with non-polynomial # Fp-point counts as a latex compatible string. # The main function we apply to all charts. # Get all the chart data from extraction, and flatten it down. # A function to build the F_p-table of the varieties where we guessed the # Fp-point count with polynomials. # The main function we apply to all charts. # Get all the chart data from extraction, and flatten it down. # A function to build the entire F_p-table as a latex compatible string. # The main function we apply to all charts. # is_poly, f = _guess_polynomial(X[1][1]["simplified_ring"], X[1][1]["simplified_system"]) # if is_poly: #     info += "{\\footnotesize " + _format_poly(f) + "}" # else: # Get all the chart data from extraction, and flatten it down. # Put everything together and return a string. # A function to build the entire unique F_p-table as a latex compatible string. # The main function we apply to all charts. # is_poly, f = _guess_polynomial(X[1][1]["simplified_ring"], X[1][1]["simplified_system"]) # if is_poly: #     info += "{\\footnotesize " + _format_poly(f) + "}" # else: # Get all the chart data from extraction, and flatten it down. # Put everything together and return a string. The main integral we aim to solve is:         \\begin{equation}             %s \\int_{S} %s \,|\mathrm{d}X|,         \\end{equation}         where $S$ is the subset of $\\mathbb{Z}_p^{%s}$ such that          %s We use %s charts, %s of which are leaves. There are a total of %s         integrals to solve. # ============================================================================== #   Main function # ============================================================================== # The following is a function that outputs a tex file. The tex file provides # information concerning the polynomials associated to the atlas A for which we # cannot automatically determine the number of F_p-rational points. # Take care of input # Make sure the file string is formatted correctly. # Determine the F_p-rational points of the atlas. # These are stored with the intersection lattices. # If these were previously computed, then nothing happens here. # Get the charts with a vertex with non-polynomial point count. # A function we apply to the nonpoly charts. If it guesses a poly it will # replace the non-guess with a polynomial in X. # Build the non-polynomial table # Build the estimate table # Build the entire table # Build the entire unique table # The following is a function that outputs a tex file. The tex file provides # information concerning the integrals associated to the atlas A. # Make sure the file string is formatted correctly.