https://gitlab.inria.fr/cado-nfs/cado-nfs
Raw File
Tip revision: c5b20eac12ea225a325d582923ef058832cda28e authored by Emmanuel Thomé on 06 August 2021, 16:52:09 UTC
Merge branch 'try-to-fix-30020' into 'master'
Tip revision: c5b20ea
cado-nfs.py
#!/usr/bin/env python3
import os
import sys
import logging

import re

# THIS PART MUST BE EXACTLY IDENTICAL IN cado-nfs.py and cado-nfs-client.py

# Three possible locations for this script
#
# The installed path. Then we should rely on the @-escaped paths, and
# determine the location of all our utility stuff based on that.
#
# The build directory. We rely on the presence of a magic file called
# source-location.txt, and we fetch the python source code from there
#
# The source tree. We call the ./scripts/build_environment.sh script to
# determine where the binaries are being put.

import subprocess
import locale

pathdict=dict()

one_pyfile_example_subpath = "scripts/cadofactor/workunit.py"

def detect_installed_tree(pathdict):
    mydir = os.path.normpath(os.path.dirname(sys.argv[0]))
    md = mydir.split(os.path.sep)
    install_tree = mydir
    bd = "@BINSUFFIX@".split(os.path.sep)
    while md and bd and md[-1] == bd[-1]:
        md.pop()
        bd.pop()
        install_tree = os.path.normpath(os.path.join(install_tree, ".."))
    if bd:
        if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"):
            print("{} does not end in @BINSUFFIX@".format(mydir))
        return False
    example = os.path.join(install_tree, "@LIBSUFFIX@", one_pyfile_example_subpath)
    t = os.path.exists(example)
    if not t:
        if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"):
            print("{} does not exist".format(example))
        return False

    # make all this relocatable, it doesn't cost us much.
    # (note though that the rpaths in the binaries are likely to still
    # contain absolute paths)
    pathdict["pylib"] = os.path.join(install_tree, "@LIBSUFFIX@/scripts/cadofactor")
    pathdict["data"]  = os.path.join(install_tree, "@DATASUFFIX@")
    pathdict["lib"]   = os.path.join(install_tree, "@LIBSUFFIX@")
    pathdict["bin"]   = os.path.join(install_tree, "@BINSUFFIX@")

    if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"):
        print("cado-nfs running in installed tree")
    return True

def detect_build_tree(pathdict):
    # source-location.txt is created by our build system, and can be used
    # *ONLY* when we call this script from the build directory. We don't
    # want this to perspire in any installed file, of course.
    mydir = os.path.normpath(os.path.dirname(sys.argv[0]))
    source_location_subpath = "source-location.txt"
    source_location_file = os.path.join(mydir, source_location_subpath)
    if not os.path.exists(source_location_file):
        if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"):
            print("{} does not exist".format(source_location_file))
        return False

    # ok, we're in the build tree, apparently
    source_tree = open(source_location_file, "r").read().strip()

    pathdict["pylib"] = os.path.join(source_tree, "scripts/cadofactor")
    pathdict["data"] = os.path.join(source_tree, "parameters")
    pathdict["lib"] = mydir
    pathdict["bin"] = mydir

    if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"):
        print("cado-nfs running in build tree")
    return True

def detect_source_tree(pathdict):
    mydir = os.path.normpath(os.path.dirname(sys.argv[0]))
    t = os.path.exists(os.path.join(mydir, one_pyfile_example_subpath))
    helper = os.path.join(mydir, "scripts/build_environment.sh")
    if not os.path.exists(helper):
        if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"):
            print("{} does not exist".format(helper))
        return False
    pipe = subprocess.Popen([helper, "--show"], stdout=subprocess.PIPE)
    loc = locale.getdefaultlocale()[1]
    if not loc:
        loc="ascii"
    output = pipe.communicate()[0].decode(loc)
    cado_bin_path = [x.split("=",2)[1] for x in output.split("\n") if re.match("^build_tree",x)][0]
    cado_bin_path = re.sub("^\"(.*)\"$", "\\1", cado_bin_path)

    pathdict["pylib"] = os.path.join(mydir, "scripts/cadofactor")
    pathdict["data"] = os.path.join(mydir, "parameters")
    pathdict["lib"] = cado_bin_path
    pathdict["bin"] = cado_bin_path

    if os.environ.get("CADO_NFS_DEBUG_PATHDETECT"):
        print("cado-nfs running in source tree")
    return True

if detect_installed_tree(pathdict):
    pass
elif detect_build_tree(pathdict):
    pass
elif detect_source_tree(pathdict):
    pass
else:
    raise RuntimeError("We're unable to determine the location of the cado-nfs binaries and python files")

sys.path.append(pathdict["pylib"])

# END OF THE PART THAT MUST BE EXACTLY IDENTICAL IN cado-nfs.py and cado-nfs-client.py


import cadotask
import cadologger
import toplevel
import itertools
import wudb
from cadocommand import shellquote

if __name__ == '__main__':
    # Parse command line arguments
    
    # Some command-line arguments are really parsed only here, while some
    # others are relevant to the whole hierarchy of cado-nfs programs.
    # The (hairy) logic which is used to form the definitive list of
    # parameters (in the cadoparams sense) from what we got here on the
    # command line is grouped in the Cado_NFS_toplevel class, down in
    # scripts/cadofactor/toplevel.py

    toplevel_params = toplevel.Cado_NFS_toplevel()
    for key, value in pathdict.items():
        toplevel_params.setpath(key, value)
    logger = toplevel_params.logger
    parameters, db = toplevel_params.get_cooked_parameters()

    # We have to remove the credential info from the database which gets
    # stored in the parameter snapshot. We must also make sure that we
    # store this info always at the root of the param tree, or we may end
    # up do bizarre things with duplicated keys if we resume from a
    # parameter snapshot file *and* we have something on the command
    # line.
    if parameters.get_or_set_default("database", None):
        parameters.replace("database", db.uri_without_credentials)
        # do this so that the parameter does not appear unused.
        parameters.get_or_set_default("database")


    # well, this *must* exist, right ?
    name = parameters.get_or_set_default("tasks.name")
    wdir = parameters.get_or_set_default("tasks.workdir")
    
    # Add a logger to capture the command lines of programs we run
    cmdfilename = os.path.join(wdir, name + ".cmd")
    logger.addHandler(cadologger.CmdFileHandler(cmdfilename))
    
    # Add a logger to write debugging information to a log file
    filelvl = getattr(cadologger, toplevel_params.args.filelog.upper())
    logfilename = os.path.join(wdir, name + ".log")
    filehandler = cadologger.FileHandler(filename = logfilename, lvl = filelvl)
    logger.addHandler(filehandler)

    
    cmdline=" ".join([shellquote(arg, idx == 0) for idx, arg in enumerate(sys.argv)])
    cmdline=cmdline.replace(db.uri, db.uri_without_credentials)
    logger.info("Command line parameters: %s", cmdline)


    logger.debug("Root parameter dictionary:\n%s", parameters)


    # Write a snapshot of the parameters to a file
    for counter in itertools.count():
        snapshot_basename = name + ".parameters_snapshot.%d" % counter
        snapshot_filename = os.path.join(wdir, snapshot_basename)
        if not os.path.isfile(snapshot_filename):
            break
    with open(snapshot_filename, "w") as snapshot_file:
        logger.debug("Writing parameter snapshot to %s", snapshot_filename)
        snapshot_file.write(str(parameters))
        snapshot_file.write("\n")

    logger.info("If this computation gets interrupted, it can be resumed with %s %s", sys.argv[0], snapshot_filename)

    factorjob = cadotask.CompleteFactorization(db=db,
                                               parameters = parameters,
                                               path_prefix = [])

    if toplevel_params.args.verboseparam:
        logger.info("Summary of all recognized parameters\n" +
                factorjob.parameter_help)

    factors = factorjob.run()
    
    dlp_param = parameters.myparams({"dlp": False,}, "")
    dlp = dlp_param["dlp"]
    checkdlp_param = parameters.myparams({"checkdlp": True ,}, "")
    checkdlp = checkdlp_param["checkdlp"]
    target_param = parameters.myparams({"target": "",}, "")
    target = target_param["target"]
    if factors is None:
        toplevel_params.purge_temp_files(nopurge=True)
        sys.exit("Error occurred, terminating")
    else:
        toplevel_params.purge_temp_files()

    if not dlp:
        print(" ".join(factors))
    else:
        if checkdlp:
            p = int(factors[0])
            ell = int(factors[1])
            log2 = int(factors[2])
            log3 = int(factors[3])
            logger.info("Checking that log(2) and log(3) are consistent...")
            logger.info("  p = " + str(p))
            logger.info("  ell = " + str(ell))
            logger.info("  log2 = " + str(log2))
            logger.info("  log3 = " + str(log3))
            assert (p-1) % ell == 0
            assert pow(3, log2*((p-1) // ell), p) == pow(2, log3*((p-1) // ell), p)
            if target != "":
                logtarget = int(factors[4])
                logger.info("Also check log(target) vs log(2) ...")
                assert pow(int(target), log2*((p-1) // ell), p) == pow(2, logtarget*((p-1) // ell), p)
        else:
            logger.info("No check was performed. Logarithms of the factor base elements are in %s" % factorjob.request_map[cadotask.Request.GET_DLOG_FILENAME]())
        if target != "":
            logtarget = int(factors[4])
            logger.info("target = " + str(target))
            logger.info("log(target) = " + str(logtarget))
            print(str(logtarget))
        logger.info("If you want to compute a new target, run %s %s target=<target>", sys.argv[0], snapshot_filename)

back to top