From 2ec7f3dfa5025ab11080660f025adaf425bbff97 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Thu, 13 Jun 2019 06:56:15 -0400 Subject: [PATCH 01/25] separate out BertiniConfig --- naglib/bertini/config.py | 46 ++++++++++++++++ naglib/bertini/io.py | 22 ++++---- naglib/bertini/run.py | 113 +++++++++++++++++++-------------------- test/test_write_input.py | 2 +- 4 files changed, 112 insertions(+), 71 deletions(-) create mode 100644 naglib/bertini/config.py diff --git a/naglib/bertini/config.py b/naglib/bertini/config.py new file mode 100644 index 0000000..b912c2f --- /dev/null +++ b/naglib/bertini/config.py @@ -0,0 +1,46 @@ +class BertiniConfig(object): + TEVALP = -4 + TEVALPJ = -3 + TNEWTP = -2 + TNEWTPJ = -1 + TZERODIM = 0 # parallel + TPOSDIM = 1 # parallel + TSAMPLE = 2 + TMEMTEST = 3 + TPRINTWS = 4 + TPROJECT = 5 + TISOSTAB = 6 + TREGENEXT = 7 # parallel + + def __init__(self): + self._tracktype = self._tracktype_default() + self._parameterhomotopy = self._parameterhomotopy_default() + + def _parameterhomotopy_default(self): + return 0 + def _parameterhomotopy_legal(self): + return int, range(2) + def _tracktype_default(self): + return 0 + def _tracktype_legal(self): + return int, range(-4, 8) + + @property + def parameterhomotopy(self): + return self._parameterhomotopy + @parameterhomotopy.setter + def parameterhomotopy(self, val): + legal_type, legal_vals = self._parameterhomotopy_legal() + if val not in legal_vals: + raise ValueError(f"parameterhomotopy must be of type {legal_type} and take one of the following values: {','.join(map(str, legal_vals))}") + self._tracktype = legal_type(val) + + @property + def tracktype(self): + return self._tracktype + @tracktype.setter + def tracktype(self, val): + legal_type, legal_vals = self._tracktype_legal() + if val not in legal_vals: + raise ValueError(f"tracktype must be of type {legal_type} and take one of the following values: {','.join(map(str, legal_vals))}") + self._tracktype = legal_type(val) diff --git a/naglib/bertini/io.py b/naglib/bertini/io.py index b48061c..c679396 100644 --- a/naglib/bertini/io.py +++ b/naglib/bertini/io.py @@ -46,16 +46,16 @@ def read_input_file(input_file: str) -> Tuple: lines = deque([l.strip() for l in fh.readlines() if l != "\n"]) config = {} - inputs = dict(variable_group=deque(), - variable=deque(), - hom_variable_group=deque(), - pathvariable=deque(), - random=deque(), - random_real=deque(), - constant=OrderedDict(), - function=OrderedDict(), - parameter=OrderedDict(), - subfunction=OrderedDict()) + inputs = dict(variable_group=[], + variable=[], + hom_variable_group=[], + pathvariable=[], + random=[], + random_real=[], + constant={}, + parameter={}, + subfunction={}, + function=OrderedDict()) misclines = [] in_config = in_input = False @@ -557,4 +557,4 @@ def write_witness_data_file(witness_data: dict, witness_data_file: str): real, imag = P[j].as_real_imag() fh.write('{0} {1}\n'.format(real, imag)) - fh.close() \ No newline at end of file + fh.close() diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index bdb4cd8..4ce98ad 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from collections import deque +from collections import OrderedDict import os import os.path as op import subprocess @@ -7,6 +7,7 @@ import numpy as np +from naglib.bertini.config import BertiniConfig from naglib.bertini.io import read_input_file, read_witness_data_file from naglib.constants import TOL from naglib.system import BERTINI, MPIRUN, PCOUNT @@ -14,102 +15,96 @@ class BertiniRun(object): - TEVALP = -4 - TEVALPJ = -3 - TNEWTP = -2 - TNEWTPJ = -1 - TZERODIM = 0 # parallel - TPOSDIM = 1 # parallel - TSAMPLE = 2 - TMEMTEST = 3 - TPRINTWS = 4 - TPROJECT = 5 - TISOSTAB = 6 - TREGENEXT = 7 # parallel - - def __init__(self, **kwargs): + def __init__(self, config, **kwargs): """Construct a BertiniRun. Parameters ---------- + config : BertiniConfig + Options to pass to Bertini. **kwargs Keyword arguments. - config : dict - Key-value pairs of configurations - variable_group : list or deque + variable_group : list Variable group(s) - variable : list or deque + variable : list Variables - hom_variable_group : list or deque + hom_variable_group : list Homogeneous variables - pathvariable : list or deque + pathvariable : list Path variables - constant : dict - Key-value pairs of constant symbols and their values - random : list or deque + random : list Collection of complex-valued random variables - random_real : list or deque + random_real : list Collection of complex-valued random variables - function : dict - Key-value pairs of function symbols and their values + constant : dict + Key-value pairs of constant symbols and their values + subfunction : dict + Key-value pairs of subfunction symbols and their values parameter : dict Key-value pairs of parameter symbols and their values + function : OrderedDict + Key-value pairs of function symbols and their values """ - config = kwargs["config"] if "config" in kwargs else {} - if not isinstance(config, dict): - raise TypeError(f"config type '{type(config)}' not understood") + if not isinstance(config, BertiniConfig): + raise TypeError("config must be an instance of BertiniConfig") + self._config = config - variable_group = kwargs["variable_group"] if "variable_group" in kwargs else deque() - if isinstance(variable_group, list): - variable_group = deque(variable_group) - elif not isinstance(variable_group, deque): + variable_group = kwargs["variable_group"] if "variable_group" in kwargs else [] + if isinstance(variable_group, tuple): + variable_group = list(variable_group) + if not isinstance(variable_group, list): raise TypeError(f"variable_group type '{type(variable_group)}' not understood") - variable = kwargs["variable"] if "variable" in kwargs else deque() - if isinstance(variable, list): - variable = deque(variable) - if not isinstance(variable, deque): + variable = kwargs["variable"] if "variable" in kwargs else [] + if isinstance(variable, tuple): + variable = list(variable) + if not isinstance(variable, list): raise TypeError(f"variable type '{type(variable)}' not understood") - hom_variable_group = kwargs["hom_variable_group"] if "hom_variable_group" in kwargs else deque() - if isinstance(hom_variable_group, list): - hom_variable_group = deque(hom_variable_group) - if not isinstance(hom_variable_group, deque): + hom_variable_group = kwargs["hom_variable_group"] if "hom_variable_group" in kwargs else [] + if isinstance(hom_variable_group, tuple): + hom_variable_group = list(hom_variable_group) + if not isinstance(hom_variable_group, list): raise TypeError(f"hom_variable_group type '{type(hom_variable_group)}' not understood") - pathvariable = kwargs["pathvariable"] if "pathvariable" in kwargs else deque() - if isinstance(pathvariable, list): - pathvariable = deque(pathvariable) - if not isinstance(pathvariable, deque): + pathvariable = kwargs["pathvariable"] if "pathvariable" in kwargs else [] + if isinstance(pathvariable, tuple): + pathvariable = list(pathvariable) + if not isinstance(pathvariable, list): raise TypeError(f"pathvariable type '{type(pathvariable)}' not understood") - random = kwargs["random"] if "random" in kwargs else deque() - if isinstance(random, list): - random = deque(random) - if not isinstance(random, deque): + random = kwargs["random"] if "random" in kwargs else [] + if isinstance(random, tuple): + random = list(random) + if not isinstance(random, list): raise TypeError(f"random type '{type(random)}' not understood") - random_real = kwargs["random_real"] if "random_real" in kwargs else deque() - if isinstance(random_real, list): - random_real = deque(random_real) - if not isinstance(random_real, deque): + random_real = kwargs["random_real"] if "random_real" in kwargs else [] + if isinstance(random_real, tuple): + random_real = list(random_real) + if not isinstance(random_real, list): raise TypeError(f"random_real type '{type(random_real)}' not understood") - constant = kwargs["constant"] if "constant" in kwargs else {} if not isinstance(constant, dict): raise TypeError(f"constant type '{type(constant)}' not understood") - function = kwargs["function"] if "function" in kwargs else {} - if not isinstance(function, dict): - raise TypeError(f"function type '{type(function)}' not understood") + subfunction = kwargs["subfunction"] if "subfunction" in kwargs else {} + if not isinstance(subfunction, dict): + raise TypeError(f"subfunction type '{type(subfunction)}' not understood") parameter = kwargs["parameter"] if "parameter" in kwargs else {} if not isinstance(parameter, dict): raise TypeError(f"parameter type '{type(parameter)}' not understood") + function = kwargs["function"] if "function" in kwargs else OrderedDict() + if isinstance(function, dict): + function = OrderedDict(function) + if not isinstance(function, OrderedDict): + raise TypeError(f"function type '{type(function)}' not understood") + self._config = dict([(k.lower(), config[k]) for k in config]) # check tracktype, set values accordingly @@ -648,4 +643,4 @@ def tracktype(self, val): def parameter_homotopy(system: list): - pass \ No newline at end of file + pass diff --git a/test/test_write_input.py b/test/test_write_input.py index 4a4a9c3..bf87652 100644 --- a/test/test_write_input.py +++ b/test/test_write_input.py @@ -4,7 +4,7 @@ from collections import deque, OrderedDict -class TestParameterHomotopy1: +class TestAbInitio: def setup(self): self.inputs = dict(variable_group=deque(["x"]), variable=deque(), From 12527814b27dfc594799e4adb0fd55a6a8653cd9 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Thu, 13 Jun 2019 20:02:27 -0400 Subject: [PATCH 02/25] WIP: more work on Config --- naglib/bertini/config.py | 46 ------------------- naglib/bertini/input_file.py | 79 +++++++++++++++++++++++++++++++++ naglib/bertini/io.py | 24 +++------- naglib/bertini/run.py | 6 +-- test/test_parameter_homotopy.py | 15 ++++++- test/test_write_input.py | 18 ++++---- 6 files changed, 112 insertions(+), 76 deletions(-) delete mode 100644 naglib/bertini/config.py create mode 100644 naglib/bertini/input_file.py diff --git a/naglib/bertini/config.py b/naglib/bertini/config.py deleted file mode 100644 index b912c2f..0000000 --- a/naglib/bertini/config.py +++ /dev/null @@ -1,46 +0,0 @@ -class BertiniConfig(object): - TEVALP = -4 - TEVALPJ = -3 - TNEWTP = -2 - TNEWTPJ = -1 - TZERODIM = 0 # parallel - TPOSDIM = 1 # parallel - TSAMPLE = 2 - TMEMTEST = 3 - TPRINTWS = 4 - TPROJECT = 5 - TISOSTAB = 6 - TREGENEXT = 7 # parallel - - def __init__(self): - self._tracktype = self._tracktype_default() - self._parameterhomotopy = self._parameterhomotopy_default() - - def _parameterhomotopy_default(self): - return 0 - def _parameterhomotopy_legal(self): - return int, range(2) - def _tracktype_default(self): - return 0 - def _tracktype_legal(self): - return int, range(-4, 8) - - @property - def parameterhomotopy(self): - return self._parameterhomotopy - @parameterhomotopy.setter - def parameterhomotopy(self, val): - legal_type, legal_vals = self._parameterhomotopy_legal() - if val not in legal_vals: - raise ValueError(f"parameterhomotopy must be of type {legal_type} and take one of the following values: {','.join(map(str, legal_vals))}") - self._tracktype = legal_type(val) - - @property - def tracktype(self): - return self._tracktype - @tracktype.setter - def tracktype(self, val): - legal_type, legal_vals = self._tracktype_legal() - if val not in legal_vals: - raise ValueError(f"tracktype must be of type {legal_type} and take one of the following values: {','.join(map(str, legal_vals))}") - self._tracktype = legal_type(val) diff --git a/naglib/bertini/input_file.py b/naglib/bertini/input_file.py new file mode 100644 index 0000000..a95917a --- /dev/null +++ b/naglib/bertini/input_file.py @@ -0,0 +1,79 @@ +from collections import OrderedDict +from numbers import Number + +DEFAULT_CONFIGS = OrderedDict(tracktype=0, + parameterhomotopy=0) +LEGAL_VALUES = {"tracktype": lambda x: x in range(-4, 8), + "parameterhomotopy": range(0, 3)} + +class BertiniConfig(object): + TEVALP = -4 + TEVALPJ = -3 + TNEWTP = -2 + TNEWTPJ = -1 + TZERODIM = 0 # parallel + TPOSDIM = 1 # parallel + TSAMPLE = 2 + TMEMTEST = 3 + TPRINTWS = 4 + TPROJECT = 5 + TISOSTAB = 6 + TREGENEXT = 7 # parallel + + def __init__(self, **kwargs): + for arg_name in DEFAULT_CONFIGS: + if arg_name in kwargs: + arg_val = kwargs.pop(arg_name) + self.__setattr__(arg_name, arg_val) + else: + self.__setattr__(arg_name, DEFAULT_CONFIGS[arg_name]) + + if kwargs: + key, _ = kwargs.popitem() + raise AttributeError(f"'BertiniConfig' has no attribute '{key}'") + + self._validate() + + def __str__(self): + s = "CONFIG\n" + for key, val in DEFAULT_CONFIGS.items(): + instance_val = self.__getattribute__(key) + if instance_val != val: + s += f"{key}:{instance_val};\n" + s += "END;" + return s + + def _validate(self): + """Ensure combinations of parameters play nicely.""" + pass + + @property + def parameterhomotopy(self): + return self._parameterhomotopy + @parameterhomotopy.setter + def parameterhomotopy(self, val): + is_legal = LEGAL_VALUES["parameterhomotopy"] + if isinstance(val, str) or (not isinstance(val, int) and isinstance(val, Number)): + val = int(val) + + if not is_legal(val): + raise ValueError(f"parameterhomotopy must take one of the following values: {','.join(map(str, legal_vals))}") + self._parameterhomotopy = val + + @property + def tracktype(self): + return self._tracktype + @tracktype.setter + def tracktype(self, val): + is_legal = LEGAL_VALUES["tracktype"] + if isinstance(val, str) or (not isinstance(val, int) and isinstance(val, Number)): + val = int(val) + + if not is_legal(val) + raise ValueError(f"tracktype must take one of the following values: {','.join(map(str, legal_vals))}") + self._tracktype = int(val) + + +class BertiniInput(object): + def __init__(self): + pass diff --git a/naglib/bertini/io.py b/naglib/bertini/io.py index c679396..94f49d4 100644 --- a/naglib/bertini/io.py +++ b/naglib/bertini/io.py @@ -9,6 +9,7 @@ import mpmath as mp import numpy as np +from naglib.bertini.input_file import BertiniConfig, BertiniInput from naglib.exceptions import UnclassifiedException @@ -45,7 +46,7 @@ def read_input_file(input_file: str) -> Tuple: with open(input_file, "r") as fh: lines = deque([l.strip() for l in fh.readlines() if l != "\n"]) - config = {} + config = BertiniConfig() inputs = dict(variable_group=[], variable=[], hom_variable_group=[], @@ -84,21 +85,10 @@ def read_input_file(input_file: str) -> Tuple: continue if in_config: - key, val = map(lambda x: x.strip(), line.split(":")) + key, val = map(lambda l: l.strip(), line.split(":")) val = val.split("%")[0].strip(" ;") # remove comment, semicolon, trailing whitespace - if key.lower() in ["condnumthreshold", "endpointfinitethreshold", "finaltol", - "pathtruncationthreshold", "samplefactor", "securitymaxnorm", - "slicetolbeforeeg", "slicetolduringeg"]: - val = float(val) - elif key.lower() in ["coeffbound", "degreebound", "maxcodimension", "mptype", - "parameterhomotopy", "precision", "randomseed", "securitylevel", - "sharpendigits", "sharpenonly", "specificcodimension", - "tracktype", "useregeneration", "userhomotopy", "witnessgentype", - "witnesssupersetonly"]: - val = int(val) - - config[key] = val + setattr(config, key.lower(), val) elif in_input: if vargroup_re.match(line): @@ -349,7 +339,7 @@ def read_witness_data_file(witness_data_file: str) -> list: return codims -def write_input_file(inputs: dict, config: dict, input_file: str): +def write_input_file(inputs: dict, config: BertiniConfig, input_file: str): """Write a Bertini input file. Parameters @@ -369,7 +359,7 @@ def write_input_file(inputs: dict, config: dict, input_file: str): for key, val in config.items(): print(f"{key}:{val};", file=fh) - print("END", file=fh) + print("END;", file=fh) print("INPUT", file=fh) # name declarations @@ -425,7 +415,7 @@ def write_input_file(inputs: dict, config: dict, input_file: str): for key, val in inputs["function"].items(): print(f"{key} = {val};", file=fh) - print("END", file=fh) + print("END;", file=fh) def write_points_file(points: List[np.ndarray], points_file: str="") -> None: diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 4ce98ad..96f0f86 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -7,7 +7,7 @@ import numpy as np -from naglib.bertini.config import BertiniConfig +from naglib.bertini.input_file import BertiniConfig from naglib.bertini.io import read_input_file, read_witness_data_file from naglib.constants import TOL from naglib.system import BERTINI, MPIRUN, PCOUNT @@ -41,7 +41,7 @@ def __init__(self, config, **kwargs): Key-value pairs of constant symbols and their values subfunction : dict Key-value pairs of subfunction symbols and their values - parameter : dict + parameter : OrderedDict Key-value pairs of parameter symbols and their values function : OrderedDict Key-value pairs of function symbols and their values @@ -95,7 +95,7 @@ def __init__(self, config, **kwargs): if not isinstance(subfunction, dict): raise TypeError(f"subfunction type '{type(subfunction)}' not understood") - parameter = kwargs["parameter"] if "parameter" in kwargs else {} + parameter = kwargs["parameter"] if "parameter" in kwargs else OrderedDict() if not isinstance(parameter, dict): raise TypeError(f"parameter type '{type(parameter)}' not understood") diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index 7f7b440..b9de3e6 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -8,4 +8,17 @@ # def setup(self): # -wd = read_witness_data(op.join(TESTBASE, "pos_dim", "basic_pos_dim", "witness_data")) \ No newline at end of file +class TestAbInitio: + def setup(self): + self.inputs = dict(variable_group=deque(["x"]), + variable=deque(), + hom_variable_group=deque(), + pathvariable=deque(), + random=deque(), + random_real=deque(), + constant=OrderedDict(), + function=OrderedDict(f="a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))"), + parameter=OrderedDict((f"a{i}", None) for i in range(7)), + subfunction=OrderedDict()) + self.config = {"ParameterHomotopy": 1} + self.input_file = op.join(TESTBASE, "input") diff --git a/test/test_write_input.py b/test/test_write_input.py index bf87652..7affe6c 100644 --- a/test/test_write_input.py +++ b/test/test_write_input.py @@ -6,15 +6,15 @@ class TestAbInitio: def setup(self): - self.inputs = dict(variable_group=deque(["x"]), - variable=deque(), - hom_variable_group=deque(), - pathvariable=deque(), - random=deque(), - random_real=deque(), - constant=OrderedDict(), - function=OrderedDict(f="a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))"), + self.inputs = dict(variable_group=[["x"]], + variable=[], + hom_variable_group=[], + pathvariable=[], + random=[], + random_real=[], + constant={}, + subfunction={}, parameter=OrderedDict((f"a{i}", None) for i in range(7)), - subfunction=OrderedDict()) + function=OrderedDict(f="a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))")) self.config = {"ParameterHomotopy": 1} self.input_file = op.join(TESTBASE, "input") From 7542c56040a82a950e1db9699d7b7a2461bda615 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Fri, 14 Jun 2019 21:32:04 -0400 Subject: [PATCH 03/25] work on BertiniRun init: maybe a parameter homotopy in the near future --- naglib/bertini/input_file.py | 201 +++++++++++++++++++++++--- naglib/bertini/run.py | 271 +++++++++++------------------------ 2 files changed, 270 insertions(+), 202 deletions(-) diff --git a/naglib/bertini/input_file.py b/naglib/bertini/input_file.py index a95917a..36fa823 100644 --- a/naglib/bertini/input_file.py +++ b/naglib/bertini/input_file.py @@ -1,10 +1,51 @@ from collections import OrderedDict from numbers import Number -DEFAULT_CONFIGS = OrderedDict(tracktype=0, - parameterhomotopy=0) -LEGAL_VALUES = {"tracktype": lambda x: x in range(-4, 8), - "parameterhomotopy": range(0, 3)} + +def _list_of_str(obj): + return isinstance(obj, list) and all(isinstance(x, str) for x in obj) + + +def _list_of_lists_of_str(obj): + return isinstance(obj, list) and all(_list_of_str(l) for l in obj) + + +def _dict_of_type(obj, dtype): + return isinstance(obj, dict) and _list_of_str(list(obj.keys())) \ + and all((isinstance(v, dtype) or v is None) for v in obj.values()) + + +def _ordereddict_of_type(obj, dtype): + return isinstance(obj, OrderedDict) and _list_of_str(list(obj.keys())) \ + and all((isinstance(v, dtype) or v is None) for v in obj.values()) + + +PARAMETERS = OrderedDict(tracktype={"default": 0, + "is valid": lambda x: x in range(-4, 8)}, + parameterhomotopy={"default": 0, + "is valid": lambda x: x in range(0, 3)}) + +INPUT_TYPES = OrderedDict(variable_group={"default": [], + "is valid": _list_of_lists_of_str}, + variable={"default": [], + "is valid": _list_of_lists_of_str}, + hom_variable_group={"default": [], + "is valid": _list_of_lists_of_str}, + pathvariable={"default": [], + "is valid": _list_of_str}, + random={"default": [], + "is valid": _list_of_str}, + random_real={"default": [], + "is valid": _list_of_str}, + constant={"default": {}, + "is valid": lambda x: _dict_of_type(x, Number)}, + subfunction={"default": {}, + "is valid": lambda x: _dict_of_type(x, str)}, + parameter={"default": OrderedDict(), + "is valid": lambda x: _ordereddict_of_type(x, str)}, + function={"default": OrderedDict(), + "is valid": lambda x: _ordereddict_of_type(x, str)}) + class BertiniConfig(object): TEVALP = -4 @@ -21,24 +62,24 @@ class BertiniConfig(object): TREGENEXT = 7 # parallel def __init__(self, **kwargs): - for arg_name in DEFAULT_CONFIGS: + for arg_name in PARAMETERS: if arg_name in kwargs: arg_val = kwargs.pop(arg_name) self.__setattr__(arg_name, arg_val) else: - self.__setattr__(arg_name, DEFAULT_CONFIGS[arg_name]) + self.__setattr__(arg_name, PARAMETERS[arg_name]["default"]) if kwargs: key, _ = kwargs.popitem() - raise AttributeError(f"'BertiniConfig' has no attribute '{key}'") + raise AttributeError(f"BertiniConfig has no attribute '{key}'") self._validate() def __str__(self): s = "CONFIG\n" - for key, val in DEFAULT_CONFIGS.items(): + for key, val in PARAMETERS.items(): instance_val = self.__getattribute__(key) - if instance_val != val: + if instance_val != val["default"]: s += f"{key}:{instance_val};\n" s += "END;" return s @@ -47,17 +88,31 @@ def _validate(self): """Ensure combinations of parameters play nicely.""" pass + def needs_component(self): + return self.tracktype in (self.TSAMPLE, self.TMEMTEST, self.TPRINTWS, + self.TPROJECT, self.TREGENEXT) + + def needs_start_points(self): + return self.tracktype in (self.TEVALP, self.TEVALPJ, self.TNEWTP, + self.TNEWTPJ, self.TMEMTEST, self.TISOSTAB) + + def needs_sample_count(self): + return self.tracktype == self.TSAMPLE + + def needs_projection_variables(self): + return self.tracktype == self.TPROJECT + @property def parameterhomotopy(self): return self._parameterhomotopy @parameterhomotopy.setter def parameterhomotopy(self, val): - is_legal = LEGAL_VALUES["parameterhomotopy"] + is_valid = PARAMETERS["parameterhomotopy"]["is valid"] if isinstance(val, str) or (not isinstance(val, int) and isinstance(val, Number)): val = int(val) - if not is_legal(val): - raise ValueError(f"parameterhomotopy must take one of the following values: {','.join(map(str, legal_vals))}") + if not is_valid(val): + raise ValueError(f"parameterhomotopy must take one of the following values: {','.join(map(str, range(0, 3)))}") self._parameterhomotopy = val @property @@ -65,15 +120,129 @@ def tracktype(self): return self._tracktype @tracktype.setter def tracktype(self, val): - is_legal = LEGAL_VALUES["tracktype"] + is_valid = PARAMETERS["tracktype"]["is valid"] if isinstance(val, str) or (not isinstance(val, int) and isinstance(val, Number)): val = int(val) - if not is_legal(val) - raise ValueError(f"tracktype must take one of the following values: {','.join(map(str, legal_vals))}") + if not is_valid(val): + raise ValueError(f"tracktype must take one of the following values: {','.join(map(str, range(-4, 7)))}") self._tracktype = int(val) class BertiniInput(object): - def __init__(self): + def __init__(self, **kwargs): + for arg_name in INPUT_TYPES: + if arg_name in kwargs: + arg_val = kwargs.pop(arg_name) + self.__setattr__(arg_name, arg_val) + else: + self.__setattr__(arg_name, INPUT_TYPES[arg_name]["default"]) + + if kwargs: + key, _ = kwargs.popitem() + raise AttributeError(f"BertiniInput has no attribute '{key}'") + + self._validate() + + def _validate(self): pass + + @property + def variable_group(self): + return self._variable_group + @variable_group.setter + def variable_group(self, val): + is_valid = INPUT_TYPES["variable_group"] + if not is_valid(val): + raise ValueError("variable_group must be a list of lists of str") + self._variable_group = val + + @property + def variable(self): + return self._variable + @variable.setter + def variable(self, val): + is_valid = INPUT_TYPES["variable"] + if not is_valid(val): + raise ValueError("variable must be a list of lists of str") + self._variable = val + + @property + def hom_variable_group(self): + return self._hom_variable_group + @hom_variable_group.setter + def hom_variable_group(self, val): + is_valid = INPUT_TYPES["hom_variable_group"] + if not is_valid(val): + raise ValueError("hom_variable_group must be a list of lists of str") + self._hom_variable_group = val + + @property + def pathvariable(self): + return self._pathvariable + @pathvariable.setter + def pathvariable(self, val): + is_valid = INPUT_TYPES["pathvariable"] + if not is_valid(val): + raise ValueError("pathvariable must be a list of str") + self._pathvariable = val + + @property + def random(self): + return self._random + @random.setter + def random(self, val): + is_valid = INPUT_TYPES["random"] + if not is_valid(val): + raise ValueError("random must be a list of str") + self._random = val + + @property + def random_real(self): + return self._random_real + @random_real.setter + def random_real(self, val): + is_valid = INPUT_TYPES["random_real"] + if not is_valid(val): + raise ValueError("random_real must be a list of str") + self._random_real = val + + @property + def constant(self): + return self._constant + @constant.setter + def constant(self, val): + is_valid = INPUT_TYPES["constant"] + if not is_valid(val): + raise ValueError("constant must be a dict of numeric") + self._constant = val + + @property + def subfunction(self): + return self._subfunction + @subfunction.setter + def subfunction(self, val): + is_valid = INPUT_TYPES["subfunction"] + if not is_valid(val): + raise ValueError("subfunction must be a dict of str") + self._subfunction = val + + @property + def parameter(self): + return self._parameter + @parameter.setter + def parameter(self, val): + is_valid = INPUT_TYPES["parameter"] + if not is_valid(val): + raise ValueError("parameter must be an OrderedDict of str") + self._parameter = val + + @property + def function(self): + return self._function + @function.setter + def function(self, val): + is_valid = INPUT_TYPES["function"] + if not is_valid(val): + raise ValueError("function must be an OrderedDict of str") + self._function = val diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 96f0f86..e929fc2 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -15,197 +15,68 @@ class BertiniRun(object): - def __init__(self, config, **kwargs): + def __init__(self, config, inputs): """Construct a BertiniRun. Parameters ---------- config : BertiniConfig Options to pass to Bertini. - **kwargs - Keyword arguments. - - variable_group : list - Variable group(s) - variable : list - Variables - hom_variable_group : list - Homogeneous variables - pathvariable : list - Path variables - random : list - Collection of complex-valued random variables - random_real : list - Collection of complex-valued random variables - constant : dict - Key-value pairs of constant symbols and their values - subfunction : dict - Key-value pairs of subfunction symbols and their values - parameter : OrderedDict - Key-value pairs of parameter symbols and their values - function : OrderedDict - Key-value pairs of function symbols and their values + inputs : BertiniInput + Bertini input section. + **kwargs : Keyword arguments + Arguments required for specific run types. """ if not isinstance(config, BertiniConfig): raise TypeError("config must be an instance of BertiniConfig") self._config = config - variable_group = kwargs["variable_group"] if "variable_group" in kwargs else [] - if isinstance(variable_group, tuple): - variable_group = list(variable_group) - if not isinstance(variable_group, list): - raise TypeError(f"variable_group type '{type(variable_group)}' not understood") - - variable = kwargs["variable"] if "variable" in kwargs else [] - if isinstance(variable, tuple): - variable = list(variable) - if not isinstance(variable, list): - raise TypeError(f"variable type '{type(variable)}' not understood") - - hom_variable_group = kwargs["hom_variable_group"] if "hom_variable_group" in kwargs else [] - if isinstance(hom_variable_group, tuple): - hom_variable_group = list(hom_variable_group) - if not isinstance(hom_variable_group, list): - raise TypeError(f"hom_variable_group type '{type(hom_variable_group)}' not understood") - - pathvariable = kwargs["pathvariable"] if "pathvariable" in kwargs else [] - if isinstance(pathvariable, tuple): - pathvariable = list(pathvariable) - if not isinstance(pathvariable, list): - raise TypeError(f"pathvariable type '{type(pathvariable)}' not understood") - - random = kwargs["random"] if "random" in kwargs else [] - if isinstance(random, tuple): - random = list(random) - if not isinstance(random, list): - raise TypeError(f"random type '{type(random)}' not understood") - - random_real = kwargs["random_real"] if "random_real" in kwargs else [] - if isinstance(random_real, tuple): - random_real = list(random_real) - if not isinstance(random_real, list): - raise TypeError(f"random_real type '{type(random_real)}' not understood") - - constant = kwargs["constant"] if "constant" in kwargs else {} - if not isinstance(constant, dict): - raise TypeError(f"constant type '{type(constant)}' not understood") - - subfunction = kwargs["subfunction"] if "subfunction" in kwargs else {} - if not isinstance(subfunction, dict): - raise TypeError(f"subfunction type '{type(subfunction)}' not understood") - - parameter = kwargs["parameter"] if "parameter" in kwargs else OrderedDict() - if not isinstance(parameter, dict): - raise TypeError(f"parameter type '{type(parameter)}' not understood") - - function = kwargs["function"] if "function" in kwargs else OrderedDict() - if isinstance(function, dict): - function = OrderedDict(function) - if not isinstance(function, OrderedDict): - raise TypeError(f"function type '{type(function)}' not understood") - - self._config = dict([(k.lower(), config[k]) for k in config]) - - # check tracktype, set values accordingly - if "tracktype" not in config: - config["tracktype"] = 0 - - if config["tracktype"] not in range(-4, 8): - raise ValueError("TrackType must be an integer between -4 and 7 (inclusive)") - - self._parallel = self.tracktype in (self.TZERODIM, self.TPOSDIM, self.TREGENEXT) - - # check to see if tracktype jives with kwargs - msg = "" - ## start point(s) required - if self.tracktype in (self.TEVALP, self.TEVALPJ, self.TNEWTP, self.TNEWTPJ, self.TMEMTEST, self.TISOSTAB) and "start" not in kkeys: - msg = "specify a point or points to evaluate with the keyword argument 'start'" - elif "start" in kkeys: - start = kwargs["start"] - if type(start) not in (list, tuple): - start = [start] - self._start = start - ## component required - if tracktype in (self.TSAMPLE, self.TMEMTEST, self.TPRINTWS, self.TPROJECT, self.TREGENEXT) and 'component' not in kkeys: - msg = "specify a component with the keyword argument 'component'" - elif 'component' in kkeys: - self._component = kwargs['component'] - ## sample count required - if tracktype == self.TSAMPLE and 'sample' not in kkeys: - msg = "specify how many points to sample with the keyword argument `sample'" - elif tracktype == self.TSAMPLE: - self._sample = kwargs['sample'] - ## projection variables required - if tracktype == self.TPROJECT and 'projection' not in kkeys: - msg = "specify the variables onto which you wish to project with the keyword argument `projection'" - elif 'projection' in kkeys: - self._projection = kwargs['projection'] - if msg: - raise KeyError(msg) - - # tolerance - # TODO:make this mean something - if 'tol' in kkeys: - self._tol = kwargs['tol'] - else: - self._tol = TOL - - # parameter homotopy - self._parameter_homotopy = {'key':'', 'arg':0} - if 'parameterhomotopy' in ckeys: - ckeys2 = config.keys() - for k in ckeys2: - if k.lower() == 'parameterhomotopy': - self._parameter_homotopy['key'] = 'ParameterHomotopy' - self._parameter_homotopy['arg'] = config[k] # in (0,1,2) - break - - del ckeys2 - - # ensure the system jives with the call for parameter homotopy - msg = '' - if not system.parameters and self._parameter_homotopy['arg'] > 0: - msg = "you have attempted to define a parameter homotopy on a system with no parameters!" - elif system.parameters and self._parameter_homotopy['arg'] <= 0: - msg = "a parameterized system requires ParameterHomotopy either 1 or 2" - elif tracktype != self.TZERODIM and self._parameter_homotopy['arg'] > 0: - msg = "parameter homotopy only supported for zero-dimensional runs" - - if msg: - raise KeyError(msg) - - if 'start' in kkeys: - start = kwargs['start'] - if type(start) not in (tuple, list): - start = [start] - # this doesn't go in self._parameter_homotopy because other kinds of run use start files - self._start = start - if 'start_parameters' in kkeys: - startp = kwargs['start_parameters'] - if type(startp) not in (tuple, list): - startp = [startp] - self._parameter_homotopy['start parameters'] = startp - else: - startp = None - if 'final_parameters' in kkeys: - finalp = kwargs['final_parameters'] - if type(finalp) not in (tuple, list): - finalp = [finalp] - self._parameter_homotopy['final parameters'] = finalp - else: - finalp = None - - # if a system specifies one of start parameters or final parameters it must specify the other - if (startp and not finalp) or (finalp and not startp): - msg = "specify both start parameters and final parameters or neither" - raise BertiniError(msg) - - # user did not specify start or final parameters - if 'parameterhomotopy' in ckeys and self._parameter_homotopy['arg'] > 1: - if not (startp or finalp): - msg = "specify start and/or final parameters with the keyword arguments `start_parameters' and/or `final_parameters'" - raise KeyError(msg) + if not isinstance(inputs, BertiniInput): + raise TypeError("inputs must be an instance of BertiniInput") + self._inputs = inputs + + # can use MPI for these types of run + self._parallel = self.tracktype in (config.TZERODIM, config.TPOSDIM, config.TREGENEXT) + + if config.needs_start_points(): + if "start" not in kwargs: + raise ValueError("specify a point or points to evaluate with the keyword argument 'start'") + self.start = kwargs["start"] + + if config.needs_component(): + if "component" not in kwargs: + raise ValueError("specify a component with the keyword argument 'component'") + self._component = kwargs["component"] + + if config.needs_sample_count(): + if "sample" not in kwargs: + raise ValueError("specify how many points to sample with the keyword argument 'sample'") + self._sample = kwargs["sample"] + + if config.needs_projection_variables(): + if "projection" not in kwargs: + raise ValueError("specify the variables onto which you wish to project with the keyword argument 'projection'") + self._projection = kwargs["projection"] + + # a setting of ParameterHomotopy > 0 requires parameters + if config.parameterhomotopy > 0 and not inputs.parameters: + raise ValueError("you are attempting a parameter homotopy with no parameters") + + # conversely, the presence of parameters requires ParameterHomotopy > 0 + if inputs.parameters and config.parameterhomotopy == 0: + raise ValueError("your system has parameters but you have not specified a parameter homotopy") + + # parameterhomotopy:2 requires start and final params + if config.parameterhomotopy == 2: + if "start_parameters" in kwargs: + self.start_parameters = kwargs["start_parameters"] + else: + raise ValueError("you have selected parameterhomotopy:2 but you have not given start parameters") + if "final_parameters" in kwargs: + self.final_parameters = kwargs["final_parameters"] + else: + raise ValueError("you have selected parameterhomotopy:2 but you have not given final parameters") self._dirname = tempfile.mkdtemp() self._bertini = BERTINI @@ -632,14 +503,42 @@ def output(self): return self._output @property - def tracktype(self): - return self._config["tracktype"] - @tracktype.setter - def tracktype(self, val): - if val not in range(-4, 8): - raise ValueError("tracktype must be an integer between -4 and 7 (inclusive)") + def start_parameters(self): + if hasattr(self, "_start_parameters"): + return self._start_parameters + else: + return np.zeros(0, dtype=np.complex) + @start_parameters.setter + def start_parameters(self, val): + if self.config.parameterhomotopy != 2: + raise ValueError("only specify start_parameters for parameterhomotopy:2") + if not isinstance(val, np.ndarray): + raise TypeError("expected a numpy array") + if val.size != len(self.inputs.parameters): + raise ValueError(f"expected {len(self.inputs.parameters)} parameters but you specifed {val.size}") + + self._start_parameters = val.as_type(np.complex) + + @property + def final_parameters(self): + if hasattr(self, "_final_parameters"): + return self._final_parameters + else: + return np.zeros(0, dtype=np.complex) + @final_parameters.setter + def final_parameters(self, val): + if self.config.parameterhomotopy != 2: + raise ValueError("only specify final_parameters for parameterhomotopy:2") + if not isinstance(val, np.ndarray): + raise TypeError("expected a numpy array") + if val.size != len(self.inputs.parameters): + raise ValueError(f"expected {len(self.inputs.parameters)} parameters but you specifed {val.size}") + + self._final_parameters = val.as_type(np.complex) - self._config["tracktype"] = int(val) + @property + def tracktype(self): + return self.config.tracktype def parameter_homotopy(system: list): From e620f28ce84ed4a2d9297e2c0efbbd05c1f59073 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Mon, 17 Jun 2019 21:51:55 -0400 Subject: [PATCH 04/25] get some tests going --- .gitignore | 1 + naglib/bertini/input_file.py | 63 ++++++++++++++++++------------- naglib/bertini/run.py | 66 ++++++++++++++++++++++++--------- setup.py | 12 ++++++ test/.coveragerc | 11 ++++++ test/context.py | 3 ++ test/test_input_file.py | 20 ++++++++++ test/test_parameter_homotopy.py | 31 ++++++---------- tox.ini | 2 - 9 files changed, 145 insertions(+), 64 deletions(-) create mode 100644 setup.py create mode 100644 test/.coveragerc create mode 100644 test/context.py create mode 100644 test/test_input_file.py diff --git a/.gitignore b/.gitignore index d49391c..7532eb6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea/ .spyproject/ __pycache__ diff --git a/naglib/bertini/input_file.py b/naglib/bertini/input_file.py index 36fa823..ec448b0 100644 --- a/naglib/bertini/input_file.py +++ b/naglib/bertini/input_file.py @@ -12,12 +12,12 @@ def _list_of_lists_of_str(obj): def _dict_of_type(obj, dtype): return isinstance(obj, dict) and _list_of_str(list(obj.keys())) \ - and all((isinstance(v, dtype) or v is None) for v in obj.values()) + and all((isinstance(v, dtype) or v is None) for v in obj.values()) def _ordereddict_of_type(obj, dtype): return isinstance(obj, OrderedDict) and _list_of_str(list(obj.keys())) \ - and all((isinstance(v, dtype) or v is None) for v in obj.values()) + and all((isinstance(v, dtype) or v is None) for v in obj.values()) PARAMETERS = OrderedDict(tracktype={"default": 0, @@ -48,18 +48,18 @@ def _ordereddict_of_type(obj, dtype): class BertiniConfig(object): - TEVALP = -4 - TEVALPJ = -3 - TNEWTP = -2 - TNEWTPJ = -1 - TZERODIM = 0 # parallel - TPOSDIM = 1 # parallel - TSAMPLE = 2 - TMEMTEST = 3 - TPRINTWS = 4 - TPROJECT = 5 - TISOSTAB = 6 - TREGENEXT = 7 # parallel + TEVALP = -4 + TEVALPJ = -3 + TNEWTP = -2 + TNEWTPJ = -1 + TZERODIM = 0 # parallel + TPOSDIM = 1 # parallel + TSAMPLE = 2 + TMEMTEST = 3 + TPRINTWS = 4 + TPROJECT = 5 + TISOSTAB = 6 + TREGENEXT = 7 # parallel def __init__(self, **kwargs): for arg_name in PARAMETERS: @@ -105,6 +105,7 @@ def needs_projection_variables(self): @property def parameterhomotopy(self): return self._parameterhomotopy + @parameterhomotopy.setter def parameterhomotopy(self, val): is_valid = PARAMETERS["parameterhomotopy"]["is valid"] @@ -112,12 +113,14 @@ def parameterhomotopy(self, val): val = int(val) if not is_valid(val): - raise ValueError(f"parameterhomotopy must take one of the following values: {','.join(map(str, range(0, 3)))}") + raise ValueError( + f"parameterhomotopy must take one of the following values: {','.join(map(str, range(0, 3)))}") self._parameterhomotopy = val @property def tracktype(self): return self._tracktype + @tracktype.setter def tracktype(self, val): is_valid = PARAMETERS["tracktype"]["is valid"] @@ -150,9 +153,10 @@ def _validate(self): @property def variable_group(self): return self._variable_group + @variable_group.setter def variable_group(self, val): - is_valid = INPUT_TYPES["variable_group"] + is_valid = INPUT_TYPES["variable_group"]["is valid"] if not is_valid(val): raise ValueError("variable_group must be a list of lists of str") self._variable_group = val @@ -160,9 +164,10 @@ def variable_group(self, val): @property def variable(self): return self._variable + @variable.setter def variable(self, val): - is_valid = INPUT_TYPES["variable"] + is_valid = INPUT_TYPES["variable"]["is valid"] if not is_valid(val): raise ValueError("variable must be a list of lists of str") self._variable = val @@ -170,9 +175,10 @@ def variable(self, val): @property def hom_variable_group(self): return self._hom_variable_group + @hom_variable_group.setter def hom_variable_group(self, val): - is_valid = INPUT_TYPES["hom_variable_group"] + is_valid = INPUT_TYPES["hom_variable_group"]["is valid"] if not is_valid(val): raise ValueError("hom_variable_group must be a list of lists of str") self._hom_variable_group = val @@ -180,9 +186,10 @@ def hom_variable_group(self, val): @property def pathvariable(self): return self._pathvariable + @pathvariable.setter def pathvariable(self, val): - is_valid = INPUT_TYPES["pathvariable"] + is_valid = INPUT_TYPES["pathvariable"]["is valid"] if not is_valid(val): raise ValueError("pathvariable must be a list of str") self._pathvariable = val @@ -190,9 +197,10 @@ def pathvariable(self, val): @property def random(self): return self._random + @random.setter def random(self, val): - is_valid = INPUT_TYPES["random"] + is_valid = INPUT_TYPES["random"]["is valid"] if not is_valid(val): raise ValueError("random must be a list of str") self._random = val @@ -200,9 +208,10 @@ def random(self, val): @property def random_real(self): return self._random_real + @random_real.setter def random_real(self, val): - is_valid = INPUT_TYPES["random_real"] + is_valid = INPUT_TYPES["random_real"]["is valid"] if not is_valid(val): raise ValueError("random_real must be a list of str") self._random_real = val @@ -210,9 +219,10 @@ def random_real(self, val): @property def constant(self): return self._constant + @constant.setter def constant(self, val): - is_valid = INPUT_TYPES["constant"] + is_valid = INPUT_TYPES["constant"]["is valid"] if not is_valid(val): raise ValueError("constant must be a dict of numeric") self._constant = val @@ -220,9 +230,10 @@ def constant(self, val): @property def subfunction(self): return self._subfunction + @subfunction.setter def subfunction(self, val): - is_valid = INPUT_TYPES["subfunction"] + is_valid = INPUT_TYPES["subfunction"]["is valid"] if not is_valid(val): raise ValueError("subfunction must be a dict of str") self._subfunction = val @@ -230,9 +241,10 @@ def subfunction(self, val): @property def parameter(self): return self._parameter + @parameter.setter def parameter(self, val): - is_valid = INPUT_TYPES["parameter"] + is_valid = INPUT_TYPES["parameter"]["is valid"] if not is_valid(val): raise ValueError("parameter must be an OrderedDict of str") self._parameter = val @@ -240,9 +252,10 @@ def parameter(self, val): @property def function(self): return self._function + @function.setter def function(self, val): - is_valid = INPUT_TYPES["function"] + is_valid = INPUT_TYPES["function"]["is valid"] if not is_valid(val): raise ValueError("function must be an OrderedDict of str") self._function = val diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index e929fc2..3bc5b44 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -1,21 +1,37 @@ # -*- coding: utf-8 -*- -from collections import OrderedDict import os import os.path as op import subprocess +import sys import tempfile import numpy as np -from naglib.bertini.input_file import BertiniConfig +from typing import AnyStr, Union + +from naglib.bertini.input_file import BertiniConfig, BertiniInput from naglib.bertini.io import read_input_file, read_witness_data_file from naglib.constants import TOL from naglib.system import BERTINI, MPIRUN, PCOUNT from naglib.exceptions import BertiniError, NoBertiniException +def _which(exe: AnyStr) -> Union[AnyStr, None]: + if sys.platform == "win32": + which_exe = "where.exe" + else: + which_exe = "which" + + try: + path = subprocess.check_output([which_exe, exe], stderr=subprocess.DEVNULL).splitlines()[0].decode() + except subprocess.CalledProcessError: + path = None + + return path + + class BertiniRun(object): - def __init__(self, config, inputs): + def __init__(self, config, inputs, **kwargs): """Construct a BertiniRun. Parameters @@ -28,9 +44,7 @@ def __init__(self, config, inputs): Arguments required for specific run types. """ - if not isinstance(config, BertiniConfig): - raise TypeError("config must be an instance of BertiniConfig") - self._config = config + self.config = config if not isinstance(inputs, BertiniInput): raise TypeError("inputs must be an instance of BertiniInput") @@ -60,11 +74,11 @@ def __init__(self, config, inputs): self._projection = kwargs["projection"] # a setting of ParameterHomotopy > 0 requires parameters - if config.parameterhomotopy > 0 and not inputs.parameters: + if config.parameterhomotopy > 0 and not inputs.parameter: raise ValueError("you are attempting a parameter homotopy with no parameters") # conversely, the presence of parameters requires ParameterHomotopy > 0 - if inputs.parameters and config.parameterhomotopy == 0: + if inputs.parameter and config.parameterhomotopy == 0: raise ValueError("your system has parameters but you have not specified a parameter homotopy") # parameterhomotopy:2 requires start and final params @@ -78,12 +92,17 @@ def __init__(self, config, inputs): else: raise ValueError("you have selected parameterhomotopy:2 but you have not given final parameters") - self._dirname = tempfile.mkdtemp() - self._bertini = BERTINI - self._system = system - self._config = config + if "bertini_path" in kwargs: + if not op.isfile(kwargs["bertini_path"]): + raise OSError(f"didn't find Bertini at '{kwargs['bertini_path']}'") + self._bertini = kwargs["bertini_path"] + else: + bertini = _which("bertini") + if bertini is None: + raise OSError("couldn't find a bertini executable and you didn't specify one") + self._bertini = bertini + self._complete = False - self._inputf = [] def _recover_components(self, witness_data): """ @@ -483,6 +502,16 @@ def bertini(self): def bertini(self, bert): self._bertini = bert + @property + def config(self): + return self._config + + @config.setter + def config(self, val): + if not isinstance(val, BertiniConfig): + raise TypeError("config must be an instance of BertiniConfig") + self._config = val + @property def complete(self): return self._complete @@ -490,6 +519,7 @@ def complete(self): @property def dirname(self): return self._dirname + @dirname.setter def dirname(self, name): self._dirname = name @@ -508,14 +538,15 @@ def start_parameters(self): return self._start_parameters else: return np.zeros(0, dtype=np.complex) + @start_parameters.setter def start_parameters(self, val): if self.config.parameterhomotopy != 2: raise ValueError("only specify start_parameters for parameterhomotopy:2") if not isinstance(val, np.ndarray): raise TypeError("expected a numpy array") - if val.size != len(self.inputs.parameters): - raise ValueError(f"expected {len(self.inputs.parameters)} parameters but you specifed {val.size}") + if val.size != len(self.inputs.parameter): + raise ValueError(f"expected {len(self.inputs.parameter)} parameters but you specifed {val.size}") self._start_parameters = val.as_type(np.complex) @@ -525,14 +556,15 @@ def final_parameters(self): return self._final_parameters else: return np.zeros(0, dtype=np.complex) + @final_parameters.setter def final_parameters(self, val): if self.config.parameterhomotopy != 2: raise ValueError("only specify final_parameters for parameterhomotopy:2") if not isinstance(val, np.ndarray): raise TypeError("expected a numpy array") - if val.size != len(self.inputs.parameters): - raise ValueError(f"expected {len(self.inputs.parameters)} parameters but you specifed {val.size}") + if val.size != len(self.inputs.parameter): + raise ValueError(f"expected {len(self.inputs.parameter)} parameters but you specifed {val.size}") self._final_parameters = val.as_type(np.complex) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..ba7154b --- /dev/null +++ b/setup.py @@ -0,0 +1,12 @@ +from setuptools import setup + +setup( + name='naglib', + version='0.1.0', + packages=['naglib', 'naglib.core', 'naglib.bertini'], + url='https://github.com/aliddell/naglib', + license='BSD', + author='Alan', + author_email='alan @t liddells d.t org', + description='Library for numerical algebraic geometry, mostly a wrapper for Bertini classic' +) diff --git a/test/.coveragerc b/test/.coveragerc new file mode 100644 index 0000000..87937af --- /dev/null +++ b/test/.coveragerc @@ -0,0 +1,11 @@ +[report] +exclude_lines = + pragma: no cover + def __repr__ + if self.debug: + if settings.DEBUG + raise AssertionError + raise NotImplementedError + if 0: + if __name__ == .__main__.: +show_missing = true diff --git a/test/context.py b/test/context.py new file mode 100644 index 0000000..f800c96 --- /dev/null +++ b/test/context.py @@ -0,0 +1,3 @@ +import os.path as op + +TESTBASE = op.abspath(op.join(op.dirname(__file__), "..")) diff --git a/test/test_input_file.py b/test/test_input_file.py new file mode 100644 index 0000000..c0d2ab8 --- /dev/null +++ b/test/test_input_file.py @@ -0,0 +1,20 @@ +from context import op, TESTBASE + +from collections import OrderedDict + +from naglib.bertini.input_file import BertiniInput, BertiniConfig + + +def test_inputs_parameter_homotopy(): + inputs = BertiniInput(variable_group=[["x"]], + parameter=OrderedDict((f"a{i}", None) for i in range(7)), + function=OrderedDict(f="a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))")) + assert inputs.variable_group == [["x"]] + assert "a0" in inputs.parameter and inputs.parameter["a0"] is None + assert "a1" in inputs.parameter and inputs.parameter["a1"] is None + assert "a2" in inputs.parameter and inputs.parameter["a2"] is None + assert "a3" in inputs.parameter and inputs.parameter["a3"] is None + assert "a4" in inputs.parameter and inputs.parameter["a4"] is None + assert "a5" in inputs.parameter and inputs.parameter["a5"] is None + assert "a6" in inputs.parameter and inputs.parameter["a6"] is None + assert inputs.function["f"] == "a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))" diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index b9de3e6..26f0895 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -1,24 +1,15 @@ -# -*- coding: utf-8 -*- - from context import op, TESTBASE -from naglib.bertini.io import read_witness_data +from collections import OrderedDict + +from naglib.bertini.run import BertiniRun +from naglib.bertini.input_file import BertiniInput, BertiniConfig + -#class TestReadWitnessData: -# def setup(self): -# +def test_ab_initio(): + inputs = BertiniInput(variable_group=[["x"]], + parameter=OrderedDict((f"a{i}", None) for i in range(7)), + function=OrderedDict(f="a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))")) -class TestAbInitio: - def setup(self): - self.inputs = dict(variable_group=deque(["x"]), - variable=deque(), - hom_variable_group=deque(), - pathvariable=deque(), - random=deque(), - random_real=deque(), - constant=OrderedDict(), - function=OrderedDict(f="a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))"), - parameter=OrderedDict((f"a{i}", None) for i in range(7)), - subfunction=OrderedDict()) - self.config = {"ParameterHomotopy": 1} - self.input_file = op.join(TESTBASE, "input") + config = BertiniConfig(parameterhomotopy=1) + brun = BertiniRun(config, inputs) diff --git a/tox.ini b/tox.ini index 37a6fe8..97ea8d9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,6 @@ [tox] envlist = py36,py37,doc,dist -[pytest] -addopts=-s --cov-conf test/.coveragerc --cov=naglib test/ --doctest-modules --open-files [testenv:py36] deps = From 8636fbe5b13df5948cc1abb048870cb37ca20433 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Mon, 17 Jun 2019 22:16:21 -0400 Subject: [PATCH 05/25] add stub README --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..413a4c5 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# NAGlib + +NAGlib is a Python library for numerical algebraic geometry. +Mostly, it's just a wrapper around [Bertini](https://bertini.nd.edu) (sold separately). + +## Installing NAGlib + +Don't install NAGlib. +It's not ready yet. +If you want something right now and you're into Julia, you might try [Bertini.jl](https://github.com/PBrdng/Bertini.jl). \ No newline at end of file From c5f07dc07adb1f41a6f2ea4ede054cd599655db5 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Mon, 17 Jun 2019 22:54:39 -0400 Subject: [PATCH 06/25] WIP: using BertiniInput/BertiniConfig in write/run --- environment.yml | 1 + naglib/bertini/io.py | 17 +++++++---------- naglib/bertini/run.py | 32 ++++++++++++++++++++++++++------ naglib/environment.yml | 9 --------- test/context.py | 5 ++++- test/test_input_file.py | 2 +- test/test_parameter_homotopy.py | 3 ++- 7 files changed, 41 insertions(+), 28 deletions(-) delete mode 100644 naglib/environment.yml diff --git a/environment.yml b/environment.yml index 265f051..979e499 100644 --- a/environment.yml +++ b/environment.yml @@ -5,3 +5,4 @@ channels: dependencies: - python=3.* - numpy +- mpmath \ No newline at end of file diff --git a/naglib/bertini/io.py b/naglib/bertini/io.py index 94f49d4..8ef9570 100644 --- a/naglib/bertini/io.py +++ b/naglib/bertini/io.py @@ -339,15 +339,15 @@ def read_witness_data_file(witness_data_file: str) -> list: return codims -def write_input_file(inputs: dict, config: BertiniConfig, input_file: str): +def write_input_file(inputs: BertiniInput, config: BertiniConfig, input_file: str): """Write a Bertini input file. Parameters ---------- - inputs : dict - Key-value pairs of input values. - config : dict - Key-value pairs of config values. + inputs : BertiniInput + Input values. + config : BertiniConfig + Config values. input_file : str Path to input file. """ @@ -355,12 +355,10 @@ def write_input_file(inputs: dict, config: BertiniConfig, input_file: str): with open(input_file, "w") as fh: # config section print("CONFIG", file=fh) - - for key, val in config.items(): - print(f"{key}:{val};", file=fh) - + print(config, file=fh) print("END;", file=fh) + # TODO: pick up here print("INPUT", file=fh) # name declarations if inputs["variable_group"]: @@ -393,7 +391,6 @@ def write_input_file(inputs: dict, config: BertiniConfig, input_file: str): if inputs["constant"]: print(f"constant {','.join(inputs['constant'].keys())};", file=fh) - print(f"function {','.join(inputs['function'].keys())};", file=fh) # optional assignments (parameters, constants, &c.) diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 3bc5b44..beb402f 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -7,16 +7,15 @@ import numpy as np -from typing import AnyStr, Union +from typing import Union from naglib.bertini.input_file import BertiniConfig, BertiniInput -from naglib.bertini.io import read_input_file, read_witness_data_file -from naglib.constants import TOL +from naglib.bertini.io import read_input_file, read_witness_data_file, write_input_file from naglib.system import BERTINI, MPIRUN, PCOUNT from naglib.exceptions import BertiniError, NoBertiniException -def _which(exe: AnyStr) -> Union[AnyStr, None]: +def _which(exe: str) -> Union[str, None]: if sys.platform == "win32": which_exe = "where.exe" else: @@ -206,8 +205,6 @@ def _recover_data(self): if not self._complete: return - from naglib.bertini.fileutils import read_points_file - from naglib.utils import striplines dirname = self._dirname system = self._system tol = self._tol @@ -495,6 +492,29 @@ def run(self, rerun_on_fail=False): return data + def setup(self, dirname: str = None): + """ + + Parameters + ---------- + dirname : str + Path to directory to run Bertini. + + Returns + ------- + + """ + if dirname is None: + self._dirname = tempfile.mkdtemp() + elif not op.isdir(dirname): + os.makedirs(dirname) + self._dirname = dirname + else: + self._dirname = dirname + + input_file = op.join(self._dirname, "input") + write_input_file(self.inputs, self.config) + @property def bertini(self): return self._bertini diff --git a/naglib/environment.yml b/naglib/environment.yml deleted file mode 100644 index 51f9487..0000000 --- a/naglib/environment.yml +++ /dev/null @@ -1,9 +0,0 @@ -name: naglib -channels: -- defaults -- conda-forge -dependencies: -- python=3.* -- numpy -- scipy -- sympy diff --git a/test/context.py b/test/context.py index f800c96..e27de3e 100644 --- a/test/context.py +++ b/test/context.py @@ -1,3 +1,6 @@ import os.path as op +import sys -TESTBASE = op.abspath(op.join(op.dirname(__file__), "..")) +print(__file__) +BASEDIR = op.abspath(op.join(op.dirname(__file__), "..")) +sys.path.insert(0, BASEDIR) diff --git a/test/test_input_file.py b/test/test_input_file.py index c0d2ab8..bcfebcd 100644 --- a/test/test_input_file.py +++ b/test/test_input_file.py @@ -1,4 +1,4 @@ -from context import op, TESTBASE +from context import op, BASEDIR from collections import OrderedDict diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index 26f0895..e544d4e 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -1,4 +1,4 @@ -from context import op, TESTBASE +from context import op, BASEDIR from collections import OrderedDict @@ -13,3 +13,4 @@ def test_ab_initio(): config = BertiniConfig(parameterhomotopy=1) brun = BertiniRun(config, inputs) + From a72d54853ea1035e454eabca729e96fb2f4533dc Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Tue, 18 Jun 2019 22:09:54 -0400 Subject: [PATCH 07/25] got a run going --- naglib/bertini/input_file.py | 73 ++++++++++++++++++++- naglib/bertini/io.py | 74 ++++------------------ naglib/bertini/run.py | 108 ++++++++++++++++++-------------- test/test_parameter_homotopy.py | 1 + test/test_write_input.py | 17 +---- 5 files changed, 147 insertions(+), 126 deletions(-) diff --git a/naglib/bertini/input_file.py b/naglib/bertini/input_file.py index ec448b0..e4cc453 100644 --- a/naglib/bertini/input_file.py +++ b/naglib/bertini/input_file.py @@ -147,8 +147,70 @@ def __init__(self, **kwargs): self._validate() + def __str__(self): + s = "INPUT\n" + # name declarations + if self.variable_group: + for variable_group in self.variable_group: + s += f"variable_group {','.join(variable_group)};\n" + + if self.variable: + for variable in self.variable: + s += f"variable {','.join(variable)};\n" + + if self.hom_variable_group: + for hom_variable_group in self.hom_variable_group: + s += f"hom_variable_group {','.join(hom_variable_group)};\n" + + if self.pathvariable: + for pathvariable in self.pathvariable: + s += f"pathvariable {','.join(pathvariable)};\n" + + if self.random: + for random in self.random: + s += f"random {','.join(random)};\n" + + if self.random_real: + for random_real in self.random_real: + s += f"random_real {','.join(random_real)};\n" + + if self.parameter: + parameters = ",".join(self.parameter.keys()) + s += f"parameter {parameters};\n" + + if self.constant: + constant = ",".join(self.constant.keys()) + s += f"constant {constant};\n" + + function = ",".join(self.function.keys()) + s += f"function {function};\n" + + # optional assignments (parameters, constants, &c.) + if self.parameter: + for key, val in self.parameter.items(): + if val is None: + continue + s += f"{key} = {val};\n" + + if self.constant: + for key, val in self.constant.items(): + s += f"{key} = {val};\n" + + if self.subfunction: + for key, val in self.subfunction.items(): + s += f"{key} = {val};\n" + + # function definitions + for key, val in self.function.items(): + s += f"{key} = {val};\n" + + s += "END;" + + return s + def _validate(self): - pass + if self.variable and (self.variable_group or self.hom_variable_group): + raise ValueError("specify EITHER variable OR some combination of variable_group and hom_variable_group") @property def variable_group(self): @@ -259,3 +321,12 @@ def function(self, val): if not is_valid(val): raise ValueError("function must be an OrderedDict of str") self._function = val + + @property + def ndims(self): + if self.variable: + nd = sum(len(v) for v in self.variable) + else: + nd = sum(len(v) for v in self.variable_group) + sum(len(v) for v in self.hom_variable_group) + + return nd diff --git a/naglib/bertini/io.py b/naglib/bertini/io.py index 8ef9570..755c1a2 100644 --- a/naglib/bertini/io.py +++ b/naglib/bertini/io.py @@ -339,7 +339,7 @@ def read_witness_data_file(witness_data_file: str) -> list: return codims -def write_input_file(inputs: BertiniInput, config: BertiniConfig, input_file: str): +def write_input_file(config: BertiniConfig, inputs: BertiniInput, input_file: str): """Write a Bertini input file. Parameters @@ -354,68 +354,13 @@ def write_input_file(inputs: BertiniInput, config: BertiniConfig, input_file: st with open(input_file, "w") as fh: # config section - print("CONFIG", file=fh) print(config, file=fh) - print("END;", file=fh) - # TODO: pick up here - print("INPUT", file=fh) - # name declarations - if inputs["variable_group"]: - for variable_group in inputs["variable_group"]: - print(f"variable_group {','.join(variable_group)};", file=fh) + # input section + print(inputs, file=fh) - if inputs["variable"]: - for variable in inputs["variable"]: - print(f"variable {','.join(variable)};", file=fh) - if inputs["hom_variable_group"]: - for hom_variable_group in inputs["hom_variable_group"]: - print(f"hom_variable_group {','.join(hom_variable_group)};", file=fh) - - if inputs["pathvariable"]: - for pathvariable in inputs["pathvariable"]: - print(f"pathvariable {','.join(pathvariable)};", file=fh) - - if inputs["random"]: - for random in inputs["random"]: - print(f"random {','.join(random)};", file=fh) - - if inputs["random_real"]: - for random_real in inputs["random_real"]: - print(f"random_real {','.join(random_real)};", file=fh) - - if inputs["parameter"]: - print(f"parameter {','.join(inputs['parameter'].keys())};", file=fh) - - if inputs["constant"]: - print(f"constant {','.join(inputs['constant'].keys())};", file=fh) - - print(f"function {','.join(inputs['function'].keys())};", file=fh) - - # optional assignments (parameters, constants, &c.) - if inputs["parameter"]: - for key, val in inputs["parameter"].items(): - if val is None: - continue - print(f"{key} = {val};", file=fh) - - if inputs["constant"]: - for key, val in inputs["constant"].items(): - print(f"{key} = {val};", file=fh) - - if inputs["subfunction"]: - for key, val in inputs["subfunction"].items(): - print(f"{key} = {val};", file=fh) - - # function definitions - for key, val in inputs["function"].items(): - print(f"{key} = {val};", file=fh) - - print("END;", file=fh) - - -def write_points_file(points: List[np.ndarray], points_file: str="") -> None: +def write_points_file(points: np.ndarray, points_file: str = "") -> None: """Print a set of points in Bertini output fashion, optionally to a file. Parameters @@ -432,13 +377,18 @@ def write_points_file(points: List[np.ndarray], points_file: str="") -> None: else: fh = sys.stdout - n_points = len(points) + if points.ndim == 1: # single point + points = points.reshape(points.size, 1) + + n_dims, n_points = points.shape + print(f"{n_points}\n", file=fh) - for p in points: + for j in range(n_points): + p = points[:, j] real, imag = p.real, p.imag - for i in range(real.size): + for i in range(n_dims): print(f"{real[i]} {imag[i]}", file=fh) print("", file=fh) diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index beb402f..3d51f3e 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import os import os.path as op +import multiprocessing import subprocess import sys import tempfile @@ -10,8 +11,8 @@ from typing import Union from naglib.bertini.input_file import BertiniConfig, BertiniInput -from naglib.bertini.io import read_input_file, read_witness_data_file, write_input_file -from naglib.system import BERTINI, MPIRUN, PCOUNT +from naglib.bertini.io import (read_input_file, read_witness_data_file, + write_input_file, write_points_file) from naglib.exceptions import BertiniError, NoBertiniException @@ -101,6 +102,13 @@ def __init__(self, config, inputs, **kwargs): raise OSError("couldn't find a bertini executable and you didn't specify one") self._bertini = bertini + if "mpi_path" in kwargs: + if not op.isfile(kwargs["mpi_path"]): + raise OSError(f"didn't find MPI executable at '{kwargs['mpi_path']}'") + self._mpi = kwargs["mpi_path"] + else: + self._mpi = _which("mpirun") + self._complete = False def _recover_components(self, witness_data): @@ -360,7 +368,6 @@ def _recover_input(self): return inlines def _write_files(self): - from os.path import exists from naglib.bertini.fileutils import fprint tracktype = self._tracktype @@ -434,64 +441,39 @@ def _write_instructions(self, lines, filename='instructions'): fh.write(line + '\n') fh.close() - def rerun(self, config={}): - if not self._complete: - return self.run() - else: - self._config.update(config) - return self.run() - def run(self, rerun_on_fail=False): # in case the user has changed any of these - if not BERTINI: - raise NoBertiniException() - - self._bertini = BERTINI - - if self._parallel and MPIRUN: - cmd = MPIRUN - arg = [cmd, '-np', str(PCOUNT), self._bertini] + if self._parallel and self._mpi is not None: + cmd = self._mpi + arg = [cmd, '-np', str(multiprocessing.cpu_count()), self._bertini] else: arg = [self._bertini] - dirname = self._dirname - - input_file = self._write_files() + self.setup() # write files - if op.exists(dirname + '/instructions'): - stdin = dirname + '/instructions' + if op.isfile(op.join(self.dirname, "/instructions")): + stdin = op.join(self.dirname, "/instructions") else: stdin = None - arg += [input_file] + arg += ["input"] + + os.chdir(self.dirname) + if stdin is not None: + stdin = open(stdin, "r") - os.chdir(dirname) - if stdin: - stdin = open(stdin, 'r') try: output = subprocess.check_output(arg, stdin=stdin, universal_newlines=True) except subprocess.CalledProcessError as e: - msg = naglib.bertini.system.proc_err_output(e.output) + msg = naglib.system.proc_err_output(e.output) raise BertiniError(msg) - if stdin: + if stdin is not None: stdin.close() self._complete = True self._output = output - if rerun_on_fail: - try: - self._inputf = self._recover_input() - data = self._recover_data() - except: - data = self.rerun() - else: - self._inputf = self._recover_input() - data = self._recover_data() - - return data - def setup(self, dirname: str = None): """ @@ -504,6 +486,7 @@ def setup(self, dirname: str = None): ------- """ + # write input file if dirname is None: self._dirname = tempfile.mkdtemp() elif not op.isdir(dirname): @@ -513,14 +496,19 @@ def setup(self, dirname: str = None): self._dirname = dirname input_file = op.join(self._dirname, "input") - write_input_file(self.inputs, self.config) + write_input_file(self.config, self.inputs, input_file) + + if self.config.parameterhomotopy == 2: + write_points_file(self.start_parameters, op.join(self._dirname, "start_parameters")) + write_points_file(self.final_parameters, op.join(self._dirname, "final_parameters")) @property def bertini(self): return self._bertini + @bertini.setter - def bertini(self, bert): - self._bertini = bert + def bertini(self, val): + self._bertini = val @property def config(self): @@ -545,13 +533,37 @@ def dirname(self, name): self._dirname = name @property - def inputf(self): - return self._inputf + def inputs(self): + return self._inputs + + @inputs.setter + def inputs(self, val): + if not isinstance(val, BertiniInput): + raise TypeError("inputs must be an instance of BertiniInput") + self._inputs = val @property def output(self): return self._output + @property + def start(self): + if hasattr(self, "_start"): + return self._start + else: + return np.zeros(0, dtype=np.complex) + + @start.setter + def start(self, val): + if not isinstance(val, np.ndarray): + raise TypeError("expected a numpy array") + if val.ndim == 1: + val = val.reshape(val.size, 1) + if val.shape[0] != self.config.ndims: + raise ValueError(f"expected points of dimension {self.config.ndims} but you specified {val.shape[0]}") + + self._start = val.as_type(np.complex) + @property def start_parameters(self): if hasattr(self, "_start_parameters"): @@ -566,7 +578,7 @@ def start_parameters(self, val): if not isinstance(val, np.ndarray): raise TypeError("expected a numpy array") if val.size != len(self.inputs.parameter): - raise ValueError(f"expected {len(self.inputs.parameter)} parameters but you specifed {val.size}") + raise ValueError(f"expected {len(self.inputs.parameter)} parameters but you specified {val.size}") self._start_parameters = val.as_type(np.complex) @@ -584,7 +596,7 @@ def final_parameters(self, val): if not isinstance(val, np.ndarray): raise TypeError("expected a numpy array") if val.size != len(self.inputs.parameter): - raise ValueError(f"expected {len(self.inputs.parameter)} parameters but you specifed {val.size}") + raise ValueError(f"expected {len(self.inputs.parameter)} parameters but you specified {val.size}") self._final_parameters = val.as_type(np.complex) diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index e544d4e..e14dea1 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -13,4 +13,5 @@ def test_ab_initio(): config = BertiniConfig(parameterhomotopy=1) brun = BertiniRun(config, inputs) + brun.run() diff --git a/test/test_write_input.py b/test/test_write_input.py index 7affe6c..b7cfd3d 100644 --- a/test/test_write_input.py +++ b/test/test_write_input.py @@ -1,20 +1,7 @@ # -*- coding: utf-8 -*- -from context import op, TESTBASE +from context import op, BASEDIR from collections import deque, OrderedDict -class TestAbInitio: - def setup(self): - self.inputs = dict(variable_group=[["x"]], - variable=[], - hom_variable_group=[], - pathvariable=[], - random=[], - random_real=[], - constant={}, - subfunction={}, - parameter=OrderedDict((f"a{i}", None) for i in range(7)), - function=OrderedDict(f="a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))")) - self.config = {"ParameterHomotopy": 1} - self.input_file = op.join(TESTBASE, "input") + From 1d0d5ee151220ee00f74c527f22378432bdf8f1d Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Tue, 18 Jun 2019 22:34:33 -0400 Subject: [PATCH 08/25] now we can tee output --- naglib/bertini/run.py | 40 ++++++++++++++++++++++++--------- test/test_parameter_homotopy.py | 2 +- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 3d51f3e..8138c54 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -441,33 +441,55 @@ def _write_instructions(self, lines, filename='instructions'): fh.write(line + '\n') fh.close() - def run(self, rerun_on_fail=False): + def run(self, dirname: str = None, tee: bool = True): + """ + + Parameters + ---------- + dirname : str, optional + Path to working directory. + tee : bool, optional + Print to stdout as you go if true. + Returns + ------- + + """ # in case the user has changed any of these if self._parallel and self._mpi is not None: cmd = self._mpi - arg = [cmd, '-np', str(multiprocessing.cpu_count()), self._bertini] + arg = [cmd, '-np', str(multiprocessing.cpu_count()), self._bertini, "input"] else: - arg = [self._bertini] + arg = [self._bertini, "input"] - self.setup() # write files + self.setup(dirname) # write files if op.isfile(op.join(self.dirname, "/instructions")): stdin = op.join(self.dirname, "/instructions") else: stdin = None - arg += ["input"] - os.chdir(self.dirname) if stdin is not None: stdin = open(stdin, "r") try: - output = subprocess.check_output(arg, stdin=stdin, universal_newlines=True) + proc = subprocess.Popen(arg, stdin=stdin, stdout=subprocess.PIPE, + universal_newlines=True) except subprocess.CalledProcessError as e: msg = naglib.system.proc_err_output(e.output) raise BertiniError(msg) + output = [] + while True: + line = proc.stdout.readline() + if line == "" and proc.poll() is not None: + break + + line = line.strip() + output.append(line) + if tee: + print(line) + if stdin is not None: stdin.close() @@ -481,10 +503,6 @@ def setup(self, dirname: str = None): ---------- dirname : str Path to directory to run Bertini. - - Returns - ------- - """ # write input file if dirname is None: diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index e14dea1..285cbfd 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -13,5 +13,5 @@ def test_ab_initio(): config = BertiniConfig(parameterhomotopy=1) brun = BertiniRun(config, inputs) - brun.run() + brun.run(dirname=op.join(BASEDIR, "test", "param-htpy")) From 2eb7adcb3a6ab73731a257777611bd0a4ad4601f Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Tue, 18 Jun 2019 22:55:24 -0400 Subject: [PATCH 09/25] recover finite_solutions, real_finite_solutions, singular_solutions, start_parameters --- naglib/bertini/io.py | 4 +- naglib/bertini/run.py | 159 ++++++-------------------------- test/test_parameter_homotopy.py | 5 +- 3 files changed, 34 insertions(+), 134 deletions(-) diff --git a/naglib/bertini/io.py b/naglib/bertini/io.py index 755c1a2..bf17189 100644 --- a/naglib/bertini/io.py +++ b/naglib/bertini/io.py @@ -4,7 +4,7 @@ import sys import re -from typing import List, Tuple +from typing import Tuple import mpmath as mp import numpy as np @@ -144,7 +144,7 @@ def read_input_file(input_file: str) -> Tuple: return config, inputs, misclines -def read_points_file(points_file: str, tol: float=None) -> np.ndarray: +def read_points_file(points_file: str, tol: float = None) -> np.ndarray: """Read points from an output file. Parameters diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 8138c54..c79f5e6 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -11,7 +11,7 @@ from typing import Union from naglib.bertini.input_file import BertiniConfig, BertiniInput -from naglib.bertini.io import (read_input_file, read_witness_data_file, +from naglib.bertini.io import (read_input_file, read_points_file, read_witness_data_file, write_input_file, write_points_file) from naglib.exceptions import BertiniError, NoBertiniException @@ -30,6 +30,10 @@ def _which(exe: str) -> Union[str, None]: return path +class BertiniResult(object): + pass + + class BertiniRun(object): def __init__(self, config, inputs, **kwargs): """Construct a BertiniRun. @@ -206,138 +210,29 @@ def _recover_components(self, witness_data): return components def _recover_data(self): - """ - recover the information pertinent to a run - """ + """Recover data from a run. + Returns + ------- + data : BertiniResult + """ if not self._complete: return - dirname = self._dirname - system = self._system - tol = self._tol - tracktype = self._tracktype - main_data = dirname + '/main_data' - fh = open(main_data, 'r') - self._main_data = striplines(fh.readlines()) - fh.close() + with open(op.join(self.dirname, "main_data"), "r") as fh: + # TODO: implement read_main_data in naglib.bertini.io to return BertiniResult + self._main_data = [l.strip() for l in fh.readlines() if l != "\n"] - projective = not not system.homvar - - if tracktype == self.TEVALP: - pass - elif tracktype == self.TEVALPJ: - pass - elif tracktype == self.TNEWTP: - pass - elif tracktype == self.TNEWTPJ: - pass - elif tracktype == self.TZERODIM: - finites = dirname + '/finite_solutions' - startp = dirname + '/start_parameters' - finite_solutions = read_points_file(finites, tol=tol, projective=projective) - - ptype = self._parameter_homotopy['arg'] - if ptype == 1: - start_parameters = read_points_file(startp, tol=tol, projective=projective) - return finite_solutions, start_parameters - - return finite_solutions - elif tracktype == self.TPOSDIM: - wdfile = dirname + '/witness_data' - self._witness_data = self.read_witness_data_file(wdfile) - components = self._recover_components(self._witness_data) - - return components - elif tracktype == self.TSAMPLE: - wdfile = dirname + '/witness_data' - self._witness_data = self.read_witness_data_file(wdfile) - samplef = dirname + '/sampled' - sampled = read_points_file(samplef, tol=tol, projective=projective) - - return sampled - elif tracktype == self.TMEMTEST: - from sympy import zeros - - wdfile = dirname + '/witness_data' - self._witness_data = self.read_witness_data_file(wdfile) - inmat = dirname + '/incidence_matrix' - fh = open(inmat, 'r') - lines = striplines(fh.readlines()) - fh.close() + result = BertiniResult() + if self.tracktype == self.config.TZERODIM: + result.finite_solutions = read_points_file(op.join(self.dirname, "finite_solutions")) + result.real_finite_solutions = read_points_file(op.join(self.dirname, "real_finite_solutions")) + result.singular_solutions = read_points_file(op.join(self.dirname, "singular_solutions")) - testcodim = self._component.codim - testcid = 0 # component_id should be 0 after write - - testp = self._start - if type(testp) not in (list, tuple): - testp = [testp] - - nonempty_codims = int(lines[0]) - lines = lines[1:] - # gather nonempty codims with component count for each - ccounts = lines[:nonempty_codims] - lines = lines[nonempty_codims:] - - ccounts = [tuple([int(d) for d in c.split(' ')]) for c in ccounts] - # ordered list of codims with component ids, for matrix - cids = [(c[0], j) for c in ccounts for j in range(c[1])] - colcount = len(cids) - dex = cids.index((testcodim, testcid)) - - numpoints = int(lines[0]) - lines = lines[1:] - - inmat = zeros(numpoints, colcount) - # populate incidence matrix - for i in range(numpoints): - line = lines[i].split(' ') - row = [int(l) for l in line] - for j in range(colcount): - inmat[i,j] = row[j] - - if numpoints == 1: - return inmat[0, dex] == 1 - else: - ret = [] - for i in range(numpoints): - ret.append(inmat[i, dex] == 1) - return ret - - elif tracktype == self.TPRINTWS: - pointsfile = dirname + '/points.out' - #sysfile = dirname + '/sys.out' - - points = read_points_file(pointsfile, tol=tol, projective=projective) - #TODO: parse linear system file and return a LinearSystem - - return points - elif tracktype == self.TPROJECT: - #TODO: implement - pass - elif tracktype == self.TISOSTAB: - config = self._config - ckeys = config.keys() - lkeys = [k.lower() for k in ckeys] - cws = None - if 'constructwitnessset' in lkeys: - for k in ckeys: - if k.lower() == 'constructwitnessset': - cws = k - break - if cws and config[cws] == 1: - wdfile = dirname + '/witness_data' - self._witness_data = self.read_witness_data_file(wdfile) - components = self._recover_components(self._witness_data) - return components - - #TODO: read isosingular_summary and maybe output_isosingular - elif tracktype == self.TREGENEXT: - wdfile = dirname + '/witness_data' - self._witness_data = self.read_witness_data_file(wdfile) - components = self._recover_components(self._witness_data) - - return components + if self.config.parameterhomotopy == 1: + result.start_parameters = read_points_file(op.join(self.dirname, "start_parameters")) + + return result def _recover_input(self): """ @@ -442,7 +337,7 @@ def _write_instructions(self, lines, filename='instructions'): fh.close() def run(self, dirname: str = None, tee: bool = True): - """ + """Run Bertini and collect results. Parameters ---------- @@ -496,8 +391,10 @@ def run(self, dirname: str = None, tee: bool = True): self._complete = True self._output = output + return self._recover_data() + def setup(self, dirname: str = None): - """ + """Write input and instructions files to working directory. Parameters ---------- @@ -517,8 +414,8 @@ def setup(self, dirname: str = None): write_input_file(self.config, self.inputs, input_file) if self.config.parameterhomotopy == 2: - write_points_file(self.start_parameters, op.join(self._dirname, "start_parameters")) - write_points_file(self.final_parameters, op.join(self._dirname, "final_parameters")) + write_points_file(self.start_parameters.reshape(1, self.start_parameters.size), op.join(self._dirname, "start_parameters")) + write_points_file(self.final_parameters.reshape(1, self.final_parameters.size), op.join(self._dirname, "final_parameters")) @property def bertini(self): diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index 285cbfd..be0a55f 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -13,5 +13,8 @@ def test_ab_initio(): config = BertiniConfig(parameterhomotopy=1) brun = BertiniRun(config, inputs) - brun.run(dirname=op.join(BASEDIR, "test", "param-htpy")) + result = brun.run(dirname=op.join(BASEDIR, "test", "param-htpy")) + + assert result.finite_solutions.shape == (1, 6) + print(result.start_parameters) From b3c9b1b78b2290227d2a524427cf1e7b5c2a4a25 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Tue, 25 Jun 2019 14:41:58 -0400 Subject: [PATCH 10/25] WIP: stash commit --- .gitignore | 26 +- naglib/bertini/input_file.py | 116 ++- naglib/bertini/io.py | 163 ++-- naglib/bertini/run.py | 156 ++-- naglib/constants.py | 2 - naglib/core/__init__.py | 0 naglib/core/algebra.py | 844 -------------------- naglib/core/base.py | 482 ----------- naglib/core/geometry.py | 208 ----- naglib/core/witnessdata.py | 364 --------- naglib/exceptions.py | 29 +- naglib/misc.py | 11 - naglib/system.py | 46 -- test/context.py | 3 + test/data/zero_dim/parameter_homotopy/input | 10 + test/test_io.py | 78 ++ test/test_parameter_homotopy.py | 38 +- test/test_write_input.py | 7 - 18 files changed, 451 insertions(+), 2132 deletions(-) delete mode 100644 naglib/constants.py delete mode 100644 naglib/core/__init__.py delete mode 100644 naglib/core/algebra.py delete mode 100644 naglib/core/base.py delete mode 100644 naglib/core/geometry.py delete mode 100644 naglib/core/witnessdata.py delete mode 100644 naglib/misc.py delete mode 100644 naglib/system.py create mode 100644 test/data/zero_dim/parameter_homotopy/input create mode 100644 test/test_io.py delete mode 100644 test/test_write_input.py diff --git a/.gitignore b/.gitignore index 7532eb6..2c2e317 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,22 @@ __pycache__ # test output -test/*/*/fail -#test/*/*/*_data -test/*/*/output* -test/*/*/rawout* -test/*/*/regenSummary -test/*/*/startRPD* -test/*/*/witness_superset* +test/data/zero_dim/**/failed_paths +test/data/zero_dim/**/finite_solutions +test/data/zero_dim/**/main_data +test/data/zero_dim/**/midpath_data +test/data/zero_dim/**/nonsingular_solutions +test/data/zero_dim/**/raw_data +test/data/zero_dim/**/raw_solutions +test/data/zero_dim/**/real_finite_solutions +test/data/zero_dim/**/singular_solutions +test/data/zero_dim/**/start +test/data/zero_dim/**/start_parameters +test/data/zero_dim/**/output + +test/data/pos_dim/*/fail +test/data/pos_dim/basic_pos_dim/witness_data +test/data/pos_dim/*/rawout* +test/data/pos_dim/*/regenSummary +test/data/pos_dim/*/startRPD* +test/data/pos_dim/*/witness_superset* diff --git a/naglib/bertini/input_file.py b/naglib/bertini/input_file.py index e4cc453..1c99abd 100644 --- a/naglib/bertini/input_file.py +++ b/naglib/bertini/input_file.py @@ -22,8 +22,36 @@ def _ordereddict_of_type(obj, dtype): PARAMETERS = OrderedDict(tracktype={"default": 0, "is valid": lambda x: x in range(-4, 8)}, + mptype={"default": 2, + "is valid": lambda x: x in range(0, 3)}, + precision={"default": 96, + "is valid": lambda x: isinstance(x, int) and x >= 64}, + coeffbound={"default": 1000., # for user-defined homotopies only + "is valid": lambda x: isinstance(x, float) and x > 0}, + degreebound={"default": 5, # for user-defined homotopies only + "is valid": lambda x: isinstance(x, int) and x > 0}, + ampmaxprec={"default": 1024, + "is valid": lambda x: isinstance(x, int) and x >= 64}, parameterhomotopy={"default": 0, - "is valid": lambda x: x in range(0, 3)}) + "is valid": lambda x: x in range(0, 3)}, + randomseed={"default": 0, + "is valid": lambda x: isinstance(x, int) and x >= 0}) + + +def _validate_param(name, val): + if name not in PARAMETERS: + return val, False + + default_val = PARAMETERS[name]["default"] + is_valid = PARAMETERS[name]["is valid"] + if not isinstance(val, type(default_val)): + try: + val = type(default_val)(val) # cast val to the same type as default_val + except ValueError: # failed to cast + return val, False + + return val, is_valid(val) + INPUT_TYPES = OrderedDict(variable_group={"default": [], "is valid": _list_of_lists_of_str}, @@ -86,7 +114,9 @@ def __str__(self): def _validate(self): """Ensure combinations of parameters play nicely.""" - pass + if self.mptype != 1 and self.precision != PARAMETERS["precision"]["default"]: + raise ValueError("you have set a non-default precision but have specified " + f"{'double' if self.mptype == 0 else 'adaptive'} precision") def needs_component(self): return self.tracktype in (self.TSAMPLE, self.TMEMTEST, self.TPRINTWS, @@ -102,32 +132,94 @@ def needs_sample_count(self): def needs_projection_variables(self): return self.tracktype == self.TPROJECT + @property + def ampmaxprec(self): + return self._ampmaxprec + + @ampmaxprec.setter + def ampmaxprec(self, val): + val, is_valid = _validate_param("ampmaxprec", val) + if not is_valid: + raise ValueError("ampmaxprec must be an integer greater than or equal to 64") + self._ampmaxprec = val + + @property + def coeffbound(self): + return self._coeffbound + + @coeffbound.setter + def coeffbound(self, val): + val, is_valid = _validate_param("coeffbound", val) + if not is_valid: + raise ValueError("coeffbound must be a positive double") + self._coeffbound = val + + @property + def degreebound(self): + return self._degreebound + + @degreebound.setter + def degreebound(self, val): + val, is_valid = _validate_param("degreebound", val) + if not is_valid: + raise ValueError("degreebound must be a positive double") + self._degreebound = val + + @property + def mptype(self): + return self._mptype + + @mptype.setter + def mptype(self, val): + val, is_valid = _validate_param("mptype", val) + if not is_valid: + raise ValueError( + f"mptype must take one of the following values: {','.join(map(str, range(0, 3)))}") + self._mptype = val + + @property def parameterhomotopy(self): return self._parameterhomotopy @parameterhomotopy.setter def parameterhomotopy(self, val): - is_valid = PARAMETERS["parameterhomotopy"]["is valid"] - if isinstance(val, str) or (not isinstance(val, int) and isinstance(val, Number)): - val = int(val) - - if not is_valid(val): + val, is_valid = _validate_param("parameterhomotopy", val) + if not is_valid: raise ValueError( f"parameterhomotopy must take one of the following values: {','.join(map(str, range(0, 3)))}") self._parameterhomotopy = val + @property + def precision(self): + return self._precision + + @precision.setter + def precision(self, val): + val, is_valid = _validate_param("precision", val) + if not is_valid: + raise ValueError("precision must be an integer greater than or equal to 64") + self._precision = val + + @property + def randomseed(self): + return self._randomseed + + @randomseed.setter + def randomseed(self, val): + val, is_valid = _validate_param("randomseed", val) + if not is_valid: + raise ValueError("randomseed must be a nonnegative integer") + self._randomseed = val + @property def tracktype(self): return self._tracktype @tracktype.setter def tracktype(self, val): - is_valid = PARAMETERS["tracktype"]["is valid"] - if isinstance(val, str) or (not isinstance(val, int) and isinstance(val, Number)): - val = int(val) - - if not is_valid(val): + val, is_valid = _validate_param("tracktype", val) + if not is_valid: raise ValueError(f"tracktype must take one of the following values: {','.join(map(str, range(-4, 7)))}") self._tracktype = int(val) diff --git a/naglib/bertini/io.py b/naglib/bertini/io.py index bf17189..bd09200 100644 --- a/naglib/bertini/io.py +++ b/naglib/bertini/io.py @@ -1,10 +1,11 @@ +from _io import TextIOWrapper from collections import deque, OrderedDict from fractions import Fraction import os.path as op import sys import re -from typing import Tuple +from typing import Tuple, Callable import mpmath as mp import numpy as np @@ -13,7 +14,7 @@ from naglib.exceptions import UnclassifiedException -def _line_to_complex(line: str, multi: bool=False) -> complex: +def _line_to_complex(line: str, multi: bool = False) -> complex: real, imag = line.split(" ") return mp.mpc(real, imag) if multi else np.complex(float(real), float(imag)) @@ -24,39 +25,29 @@ def _line_to_complex_rat(line: str) -> complex: return np.complex(Fraction(real), Fraction(imag)) -def read_input_file(input_file: str) -> Tuple: - """Parse input file. +def parse_input_file(fh: TextIOWrapper, stop_if: Callable = None) -> Tuple[BertiniConfig, BertiniInput, list]: + """Given an open file handle, read until stopping criterion is satisfied + and try to parse an input file from it. Parameters ---------- - input_file : str - Path to input file. + fh : _io.TextIOWrapper + An open file handle. + stop_if : function, optional + Stop when the next line satisfies this function. Returns ------- - config : dict + config : BertiniConfig Key-value pairs of parameters set in the CONFIG section. - inputs : dict + inputs : BertiniInput Values set in the INPUT section. """ - - if not op.isfile(op.abspath(input_file)): - raise IOError(f"Input file '{input_file}' not found") - - with open(input_file, "r") as fh: - lines = deque([l.strip() for l in fh.readlines() if l != "\n"]) + if stop_if is None: + stop_if = lambda line: line != "" config = BertiniConfig() - inputs = dict(variable_group=[], - variable=[], - hom_variable_group=[], - pathvariable=[], - random=[], - random_real=[], - constant={}, - parameter={}, - subfunction={}, - function=OrderedDict()) + inputs = BertiniInput() misclines = [] in_config = in_input = False @@ -69,8 +60,9 @@ def read_input_file(input_file: str) -> Tuple: function_re = re.compile(r"^function\s+", re.I) parameter_re = re.compile(r"^parameter\s+", re.I) - while lines: - line = lines.popleft().strip(" ;") + line = fh.readline() + while not stop_if(line): + line = line.strip(" ;") if line.lower() == "config": in_config = True @@ -86,41 +78,41 @@ def read_input_file(input_file: str) -> Tuple: if in_config: key, val = map(lambda l: l.strip(), line.split(":")) - val = val.split("%")[0].strip(" ;") # remove comment, semicolon, trailing whitespace + val = val.split("%")[0].strip(" ;") # remove comment, semicolon, trailing whitespace setattr(config, key.lower(), val) elif in_input: if vargroup_re.match(line): line = vargroup_re.sub("", line) - inputs["variable_group"].append(re.split(r",\s*", line)) + inputs.variable_group.append(re.split(r",\s*", line)) elif var_re.match(line): line = var_re.sub("", line) - inputs["variable"].append(re.split(r",\s*", line)) + inputs.variable.append(re.split(r",\s*", line)) elif homvargroup_re.match(line): line = homvargroup_re.sub("", line) - inputs["hom_variable_group"].append(re.split(r",\s*", line)) + inputs.hom_variable_group.append(re.split(r",\s*", line)) elif pathvar_re.match(line): line = pathvar_re.sub("", line) - inputs["pathvariable"].append(re.split(r",\s*", line)) + inputs.pathvariable.append(re.split(r",\s*", line)) elif random_re.match(line): line = random_re.sub("", line) - inputs["random"].append(re.split(r",\s*", line)) + inputs.random.append(re.split(r",\s*", line)) elif constant_re.match(line): line = constant_re.sub("", line) constants = re.split(r",\s*", line) for c in constants: - inputs["constant"][c] = None + inputs.constant[c] = None elif function_re.match(line): line = function_re.sub("", line) functions = re.split(r",\s*", line) for f in functions: - inputs["function"][f] = None + inputs.function[f] = None elif parameter_re.match(line): line = parameter_re.sub("", line) params = re.split(r",\s*", line) for p in params: - inputs["parameter"][p] = None + inputs.parameter[p] = None else: terms = re.split(r";\s*", line) for term in terms: @@ -132,19 +124,46 @@ def read_input_file(input_file: str) -> Tuple: misclines.append("=".join(term)) else: term, val = term - if term in inputs["constant"]: - inputs["constant"][term] = val - elif term in inputs["function"]: - inputs["function"][term] = val - elif term in inputs["parameter"]: - inputs["parameter"][term] = val + if term in inputs.constant: + inputs.constant[term] = val + elif term in inputs.function: + inputs.function[term] = val + elif term in inputs.parameter: + inputs.parameter[term] = val else: - inputs["subfunction"][term] = val + inputs.subfunction[term] = val + + line = fh.readline() return config, inputs, misclines -def read_points_file(points_file: str, tol: float = None) -> np.ndarray: +def read_input_file(input_file: str) -> Tuple[BertiniConfig, BertiniInput, list]: + """Given a path to an input file, parse its contents. + + Parameters + ---------- + input_file : str + Path to input file. + + Returns + ------- + config : BertiniConfig + Key-value pairs of parameters set in the CONFIG section. + inputs : BertiniInput + Values set in the INPUT section. + """ + + if not op.isfile(op.abspath(input_file)): + raise IOError(f"Input file '{input_file}' not found") + + with open(input_file, "r") as fh: + config, inputs, misclines = parse_input_file(fh) + + return config, inputs, misclines + + +def read_points_file(points_file: str, tol: float = None, multi: bool = False) -> np.ndarray: """Read points from an output file. Parameters @@ -154,6 +173,8 @@ def read_points_file(points_file: str, tol: float = None) -> np.ndarray: tol : float, optional If given, numbers smaller than this in absolute value will be set to 0. Otherwise, they will be left as is. + multi : bool, optional + Use a multiple precision type if true (infer precision from string length) Returns ------- @@ -166,21 +187,34 @@ def read_points_file(points_file: str, tol: float = None) -> np.ndarray: raise IOError(f"Points file '{points_file}' not found") with open(points_file, "r") as fh: - lines = [l.strip() for l in fh.readlines() if l != "\n"] + lines = [l.strip(";\n") for l in fh.readlines() if l != "\n"] - n_points = int(lines[0]) + n_points = int(lines.pop(0)) if n_points == 0: - return np.zeros(0, dtype=np.complex) # return an empty array + return np.zeros(0, dtype=np.complex) # return an empty array - lines = lines[1:] n_lines = len(lines) n_dims = n_lines // n_points - points = np.zeros((n_dims, n_points), dtype=np.complex) + if multi: # peak ahead to get an idea of precision required + r = lines[0].split(" ")[0] + if "e" in r.lower(): # remove exponent + r = r[:r.lower().index("e")] + r = r.strip("-0").replace(".", "") + + prec_est = int(np.floor(len(r) * np.log2(10))) + + if mp.mp.prec < prec_est: # only ever raise working precision + mp.mp.prec = prec_est + + if mp.mp.prec == 53: # default precision, just use doubles + multi = False + + points = np.zeros((n_dims, n_points), dtype=mp.mpc if multi else np.complex) for i in range(0, n_lines, n_dims): point_lines = lines[i:i+n_dims] - points[:, i//n_dims] = np.array([_line_to_complex(p) for p in point_lines]) + points[:, i//n_dims] = np.array([_line_to_complex(p, multi) for p in point_lines]) if tol is not None: points.imag[np.abs(points.imag) < tol] = 0 @@ -495,3 +529,34 @@ def write_witness_data_file(witness_data: dict, witness_data_file: str): fh.write('{0} {1}\n'.format(real, imag)) fh.close() + + +def extract_error_message(output: str) -> str: + """Extract Bertini error message. + + Parameters + ---------- + output : str + Bertini standard output. + + Returns + ------- + err_message: str + Just the relevant error text. + """ + lines = output.splitlines() + + idx = None + for l in lines: + if l.startswith("ERROR"): + idx = lines.index(l) + + if idx is None: + return output + else: + lines = lines[idx:-1] # remove "Bertini will now exit due to this error" + + # remove "ERROR: " + lines[0] = lines[0].replace("ERROR: ", "") + + return "\n".join(lines) diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index c79f5e6..ce1fdf5 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -12,8 +12,8 @@ from naglib.bertini.input_file import BertiniConfig, BertiniInput from naglib.bertini.io import (read_input_file, read_points_file, read_witness_data_file, - write_input_file, write_points_file) -from naglib.exceptions import BertiniError, NoBertiniException + write_input_file, write_points_file, extract_error_message) +from naglib.exceptions import BertiniError def _which(exe: str) -> Union[str, None]: @@ -225,19 +225,23 @@ def _recover_data(self): result = BertiniResult() if self.tracktype == self.config.TZERODIM: - result.finite_solutions = read_points_file(op.join(self.dirname, "finite_solutions")) - result.real_finite_solutions = read_points_file(op.join(self.dirname, "real_finite_solutions")) - result.singular_solutions = read_points_file(op.join(self.dirname, "singular_solutions")) + result.finite_solutions = read_points_file(op.join(self.dirname, "finite_solutions"), + multi=self.config.mptype != 0) + result.nonsingular_solutions = read_points_file(op.join(self.dirname, "nonsingular_solutions"), + multi=self.config.mptype != 0) + result.real_finite_solutions = read_points_file(op.join(self.dirname, "real_finite_solutions"), + multi=self.config.mptype != 0) + result.singular_solutions = read_points_file(op.join(self.dirname, "singular_solutions"), + multi=self.config.mptype != 0) if self.config.parameterhomotopy == 1: - result.start_parameters = read_points_file(op.join(self.dirname, "start_parameters")) + result.start_parameters = read_points_file(op.join(self.dirname, "start_parameters"), multi=True) + result.start = read_points_file(op.join(self.dirname, "start"), multi=self.config.mptype != 0) return result def _recover_input(self): - """ - Reads main_data and recovers the input file - needed to reproduce a run + """Read main_data and recover input needed to reproduce this run. """ filename = self._dirname + "/main_data" key = "*************** input file needed to reproduce this run ***************\n" @@ -262,72 +266,72 @@ def _recover_input(self): return inlines - def _write_files(self): - from naglib.bertini.fileutils import fprint - - tracktype = self._tracktype - dirname = self._dirname - system = self._system - if not op.exists(dirname): - os.mkdir(dirname) - - ### write the system - sysconfig = self._config.copy() - sysconfig.update({'TrackType':tracktype}) - inputf = self._write_system(system, config=sysconfig) - - ### write out `start', `start_parameters', `final_parameters' - if '_start' in dir(self): - start = self._start - if self._tracktype == self.TMEMTEST: - startfile = dirname + '/member_points' - else: - startfile = dirname + '/start' - fprint(start, startfile) - if self._parameter_homotopy: - phtpy = self._parameter_homotopy - pkeys = phtpy.keys() - if 'start parameters' in pkeys: - startp = phtpy['start parameters'] - startpfile = dirname + '/start_parameters' - fprint(startp, startpfile) - if 'final parameters' in pkeys: - finalp = phtpy['final parameters'] - finalpfile = dirname + '/final_parameters' - fprint(finalp, finalpfile) - - ### write out component information - if '_component' in dir(self): - component = self._component - #cid = component.component_id - dim = component.dim - if tracktype == self.TREGENEXT: - self._write_system(component.system, 'iold', {'TrackType':1}) - witness_data = component._construct_witness_data() - self._write_witness_data(witness_data, dirname, filename='wdold') - instructions = ['1', 'iold', 'wdold', str(dim), '0'] - self._write_instructions(instructions) - elif tracktype in (self.TSAMPLE, self.TMEMTEST, self.TPRINTWS, self.TPROJECT): - witness_data = component._construct_witness_data() - self._write_witness_data(witness_data, dirname) - if tracktype == self.TSAMPLE: - sample = self._sample - instructions = [str(dim), '0', str(sample), '0', 'sampled'] - self._write_instructions(instructions) - elif tracktype == self.TPRINTWS: - instructions = [str(dim), '0', 'points.out', 'sys.out'] - self._write_instructions(instructions) - elif tracktype == self.TPROJECT: - instructions = [str(dim), '0'] - self._write_instructions(instructions) - - ### write out projection information - projection = self._projection - projnum = ['1' if x in projection else '0' for x in system.variables] - projnum = [' '.join(projnum)] - self._write_instructions(projnum, 'projection') - - return inputf + # def _write_files(self): + # from naglib.bertini.fileutils import fprint + # + # tracktype = self._tracktype + # dirname = self._dirname + # system = self._system + # if not op.exists(dirname): + # os.mkdir(dirname) + # + # ### write the system + # sysconfig = self._config.copy() + # sysconfig.update({'TrackType':tracktype}) + # inputf = self._write_system(system, config=sysconfig) + # + # ### write out `start', `start_parameters', `final_parameters' + # if '_start' in dir(self): + # start = self._start + # if self._tracktype == self.TMEMTEST: + # startfile = dirname + '/member_points' + # else: + # startfile = dirname + '/start' + # fprint(start, startfile) + # if self._parameter_homotopy: + # phtpy = self._parameter_homotopy + # pkeys = phtpy.keys() + # if 'start parameters' in pkeys: + # startp = phtpy['start parameters'] + # startpfile = dirname + '/start_parameters' + # fprint(startp, startpfile) + # if 'final parameters' in pkeys: + # finalp = phtpy['final parameters'] + # finalpfile = dirname + '/final_parameters' + # fprint(finalp, finalpfile) + # + # ### write out component information + # if '_component' in dir(self): + # component = self._component + # #cid = component.component_id + # dim = component.dim + # if tracktype == self.TREGENEXT: + # self._write_system(component.system, 'iold', {'TrackType':1}) + # witness_data = component._construct_witness_data() + # self._write_witness_data(witness_data, dirname, filename='wdold') + # instructions = ['1', 'iold', 'wdold', str(dim), '0'] + # self._write_instructions(instructions) + # elif tracktype in (self.TSAMPLE, self.TMEMTEST, self.TPRINTWS, self.TPROJECT): + # witness_data = component._construct_witness_data() + # self._write_witness_data(witness_data, dirname) + # if tracktype == self.TSAMPLE: + # sample = self._sample + # instructions = [str(dim), '0', str(sample), '0', 'sampled'] + # self._write_instructions(instructions) + # elif tracktype == self.TPRINTWS: + # instructions = [str(dim), '0', 'points.out', 'sys.out'] + # self._write_instructions(instructions) + # elif tracktype == self.TPROJECT: + # instructions = [str(dim), '0'] + # self._write_instructions(instructions) + # + # ### write out projection information + # projection = self._projection + # projnum = ['1' if x in projection else '0' for x in system.variables] + # projnum = [' '.join(projnum)] + # self._write_instructions(projnum, 'projection') + # + # return inputf def _write_instructions(self, lines, filename='instructions'): filename = self._dirname + '/' + filename @@ -371,7 +375,7 @@ def run(self, dirname: str = None, tee: bool = True): proc = subprocess.Popen(arg, stdin=stdin, stdout=subprocess.PIPE, universal_newlines=True) except subprocess.CalledProcessError as e: - msg = naglib.system.proc_err_output(e.output) + msg = extract_error_message(e.output) raise BertiniError(msg) output = [] diff --git a/naglib/constants.py b/naglib/constants.py deleted file mode 100644 index 8885337..0000000 --- a/naglib/constants.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Tolerance""" -TOL = 1e-15 \ No newline at end of file diff --git a/naglib/core/__init__.py b/naglib/core/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/naglib/core/algebra.py b/naglib/core/algebra.py deleted file mode 100644 index a16b881..0000000 --- a/naglib/core/algebra.py +++ /dev/null @@ -1,844 +0,0 @@ -from sympy import I, Matrix as spmatrix, sympify, zeros - -import naglib.bertini -from naglib.constants import TOL -from naglib.exceptions import BertiniError, NonPolynomialException, NonHomogeneousException -from naglib.core.base import NAGObject, scalar_num, Point, AffinePoint - -class PolynomialSystem(NAGObject): - """ - A polynomial system - """ - def __init__(self, polynomials, variables=None, parameters=None, homvar=None): - """ - Initialize the PolynomialSystem object - """ - from re import sub as resub - from functools import reduce - - if type(polynomials) == str: - polynomials = [polynomials] - try: - polynomials = list(polynomials) - except TypeError: - polynomials = [polynomials] - - self._polynomials = [] - - # check if any polynomial is a string and contains '^' - for p in polynomials: - if type(p) == str: - p = resub(r'\^', r'**', p) - p = sympify(p) - self._polynomials.append(p) - - self._polynomials = spmatrix(self._polynomials) - - # check if any given functions are actually not polynomials - for p in self._polynomials: - if not p.is_polynomial(): - msg = "function {0} is not a polynomial".format(p) - raise NonPolynomialException(msg) - - # set parameters, if given... - if parameters: - try: - parameters = list(parameters) - except TypeError: - parameters = [parameters] - parameters = [sympify(p) for p in parameters] - self._parameters = spmatrix(parameters) - # ...otherwise, set parameters to empty matrix - else: - self._parameters = spmatrix() - - # set variables, if given... - if variables: - try: - variables = list(variables) - except TypeError: - variables = [variables] - variables = [sympify(v) for v in variables] - self._variables = spmatrix(variables) - # ...otherwise, determine variables from non-parameter free symbols - else: - variable_list = set() - param_set = set(self._parameters) - # gather free symbols from each polynomial - free_sym = [p.free_symbols for p in self._polynomials] - if free_sym: - variable_list = reduce(lambda x, y: x.union(y), free_sym) - # remove parameters from set of free symbols - variable_list = list(variable_list.difference(param_set)) - else: - variable_list = [] - variable_strings = [str(v) for v in variable_list] - variable_strings.sort() - variables = sympify(variable_strings) - self._variables = spmatrix(variables) - - # set homogenizing variable, if given - if homvar: - homvar = sympify(homvar) - try: # multihomogeneous? - homvar = list(homvar) - except TypeError: - homvar = [homvar] - if len(homvar) > 1: - msg = "multihomogeneous systems not yet supported" - raise NotImplementedError(msg) - - # but check to see if it's legit - if homvar[0] not in self._variables: - msg = "homogenizing variable {0} not in variables".format(homvar) - raise ValueError(msg) - - self._homvar = spmatrix(homvar) - self._domain = len(self._variables) - 1 - else: - self._homvar = spmatrix() - self._domain = len(self._variables) - - - d = [] - params = list(self._parameters) - ones = [1 for param in params] - paramsubs = zip(params,ones) - - # keep parameters out of degree calculation - for poly in self._polynomials: - p = poly.subs(paramsubs) - if p.is_number: # p should never be a number, but... - deg = 0 - else: - polyp = p.as_poly(domain='CC') - deg = polyp.total_degree() - # check if polynomial is homogeneous - if self._homvar: - polyp = p.as_poly(domain='CC') - if not polyp.is_homogeneous: - msg = "polynomial {0} is not homogeneous".format(p) - raise NonHomogeneousException(msg) - d.append(deg) - - self._degree = tuple(d) - self._num_variables = len(self._variables) - self._num_polynomials = len(self._polynomials) - - def __str__(self): - """ - x.__str__() <==> str(x) - """ - polynomials = self._polynomials - # even up the lengths of the polynomial strings - pstrs = [str(p) for p in polynomials] - #strlens = [len(f) for f in fstrs] - #maxlen = max(strlens) - #fstrs = [' '*(maxlen - len(f)) + f for f in fstrs] - #fstr = '\n'.join(['[{0}]'.format(f) for f in fstrs]) - repstr = '{' + ', '.join([str(p) for p in pstrs]) + '}' - return repstr - - def __repr__(self): - """ - x.__repr__() <==> repr(x) - """ - polynomials = list(self._polynomials) - variables = list(self._variables) - parameters = list(self._parameters) - homvar = list(self._homvar) - repstr = 'PolynomialSystem({0},{1},{2},{3})'.format(polynomials, - variables, - parameters, - homvar) - - return repstr - - def __getitem__(self, key): - """ - x.__getitem__(y) <==> x[y] - """ - polynomials = self._polynomials - return polynomials[key] - - def __getslice__(self, i, j): - """ - x.__getslice__(i,j) <==> x[i:j] - """ - polynomials = self._polynomials - return spmatrix(polynomials[i:j]) - - def __len__(self): - return len(self._polynomials) - - def __eq__(self, other): - return self.equals(other, strict=True) - - def __neg__(self): - """ - x.__neg___() <==> -x - """ - npolynomials = -self._polynomials - variables = self._variables - parameters = self._parameters - homvar = self._homvar - return PolynomialSystem(npolynomials, variables, parameters, homvar) - - def __add__(self, other): - """ - x.__add__(y) <==> x + y - """ - from functools import reduce - - if not isinstance(other, PolynomialSystem): - t = type(other) - msg = "unsupported operand type(s) for +: 'PolynomialSystem' and '{0}'".format(t) - raise TypeError(msg) - - spoly = self._polynomials - opoly = other._polynomials - spolct = len(spoly) - opolct = len(opoly) - - # different sizes of systems - if spolct != opolct: - msg = "can't add systems of different sizes; cowardly backing out" - raise ValueError(msg) - - shomvar = self._homvar - ohomvar = other._homvar - sdeg = self._degree - odeg = other._degree - - # check homogenizing variables - if shomvar and ohomvar and shomvar == ohomvar: - # both have same homogenizing variables and degrees; all is well - if sdeg == odeg: - svars = set(self._variables) - ovars = set(other._variables) - spars = set(self._parameters) - opars = set(other._parameters) - - # ensure the parameters of x are not the variables of y - if svars.intersection(opars) or spars.intersection(ovars): - msg = "variables and parameters in summands overlap; cowardly backing out" - raise ValueError(msg) - - newpoly = spoly + opoly - newpsym = [p.free_symbols for p in newpoly] - newpsym = reduce(lambda x, y: x.union(y), newpsym) - newvars = (svars.union(ovars)).intersection(newpsym) - newpars = (spars.union(opars)).intersection(newpsym) - newvars = sorted([str(v) for v in newvars]) - newpars = sorted([str(p) for p in newpars]) - newvars = sympify(newvars) - newpars = sympify(newpars) - - return PolynomialSystem(newpoly, newvars, newpars, shomvar) - else: - msg = "multihomogeneous systems not yet supported" - raise NotImplementedError(msg) - elif shomvar or ohomvar: - msg = "multihomogeneous systems not yet supported" - raise NotImplementedError(msg) - else: # no homogenizing variables - svars = set(self._variables) - ovars = set(other._variables) - spars = set(self._parameters) - opars = set(other._parameters) - - # ensure the parameters of x are not the variables of y - if svars.intersection(opars) or spars.intersection(ovars): - msg = "variables and parameters in summands overlap; cowardly backing out" - raise ValueError(msg) - - newpoly = spoly + opoly - newpsym = [p.free_symbols for p in newpoly] - newpsym = reduce(lambda x, y: x.union(y), newpsym) - newvars = (svars.union(ovars)).intersection(newpsym) - newpars = (spars.union(opars)).intersection(newpsym) - newvars = sorted([str(v) for v in newvars]) - newpars = sorted([str(p) for p in newpars]) - newvars = sympify(newvars) - newpars = sympify(newpars) - - return PolynomialSystem(newpoly, newvars, newpars) - - def __sub__(self, other): - """ - x.__sub__(y) <==> x - y - """ - if not isinstance(other, PolynomialSystem): - t = type(other) - msg = "unsupported operand type(s) for +: 'PolynomialSystem' and '{0}'".format(t) - raise TypeError(msg) - - other = -other - return self + other - - def __mul__(self, other): - """ - x.__mul__(y) <==> x*y - """ - from sympy import Add - cls = self.__class__ - - if isinstance(other, cls): - sm = self.shape[0] - om = other.shape[0] - if sm > 1 and om > 1: - from sympy import ShapeError - msg = "shape mismatch" - raise ShapeError(msg) - elif sm == 1: - spol = self.polynomials[0] - opols = other.polynomials - pols = spol*opols - elif om == 1: - opol = other.polynomials[0] - spols = self.polynomials - pols = opol*spols - - svars = set(self.variables) - ovars = set(other.variables) - spars = set(self.parameters) - opars = set(other.parameters) - - if svars.intersection(opars) or ovars.intersection(spars): - msg = "nontrivial intersection between variables and parameters" - raise ValueError(msg) - elif self._homvar != other.homvar: - msg = "multihomogeneous polynomial systems not implemented yet" - raise NotImplementedError(msg) - - variables = svars.union(ovars) - parameters = spars.union(opars) - - return cls(pols, variables, parameters, self._homvar) - elif isinstance(other, Add): - parameters = self.parameters - polynomials = self._polynomials * other - homvar = self._homvar - - return cls(polynomials, parameters=parameters, homvar=homvar) - - elif scalar_num(other): - polynomials = other*self._polynomials - variables = self._variables - parameters = self._parameters - homvar = self._homvar - if other == 0: - return PolynomialSystem(polynomials) - else: - return PolynomialSystem(polynomials, variables, parameters, homvar) - else: - t = type(other) - msg = "unsupported operand type(s) for *: 'PolynomialSystem' and '{0}'".format(t) - raise TypeError(msg) - - def __rmul__(self, other): - """ - x.__rmul__(y) <==> y*x - """ - return self.__mul__(other) - - def __div__(self, other): - """ - x.__div__(y) <==> x/y - """ - return self.__truediv__(other) - - def __truediv__(self, other): - """ - x.__truediv__(y) <==> x/y - """ - if not scalar_num(other): - t = type(other) - msg = "unsupported operand type(s) for /: 'PolynomialSystem' and '{0}'".format(t) - raise TypeError(msg) - else: - if other == 0: - msg = "division by zero" - raise ZeroDivisionError(msg) - polynomials = self._polynomials/other - variables = self._variables - parameters = self._parameters - homvar = self._homvar - return PolynomialSystem(polynomials, variables, parameters, homvar) - - def assign_parameters(self, params): - """ - Set params as parameters in self - """ - if not hasattr(params, '__iter__'): - params = [params] - params = set(sympify(params)) - - sparams = set(self._parameters).union(params) - svars = set(self._variables).difference(sparams) - - str_pars = sorted([str(p) for p in sparams]) - str_vars = sorted([str(v) for v in svars]) - - self._parameters = spmatrix(sympify(str_pars)) - self._variables = spmatrix(sympify(str_vars)) - - def cat(self, other): - """ - concatenate a polynomial at the end of self - """ - if not other: - return self - other = sympify(other) - try: - other = spmatrix(other) - except TypeError: - other = spmatrix([other]) - parameters = self._parameters - polynomials = self._polynomials - homvar = self._homvar - - newpols = polynomials.col_join(other) - return PolynomialSystem(newpols, parameters=parameters, homvar=homvar) - - def copy(self): - polynomials = self._polynomials.copy() - variables = self._variables.copy() - parameters = self._parameters.copy() - homvar = self._homvar.copy() - - return PolynomialSystem(polynomials, variables, parameters, homvar) - - def dehomogenize(self): - """ - Dehomogenize the system - - If already nonhomogeneous, return self - """ - hompolys = self._polynomials - hompolys = spmatrix([p.expand() for p in hompolys]) - homvars = self._variables - parameters = self._parameters - - if not self._homvar: - return self - else: - homvar = self._homvar[0] # this will change for multihomogeneous polynomials - - homvars = list(homvars) - dex = homvars.index(homvar) - homvars.pop(dex) - variables = spmatrix(homvars) - - polynomials = hompolys.subs({homvar:1}) - - return PolynomialSystem(polynomials, variables, parameters) - - def equals(self, other, strict=True): - """ - x.equals(y) <==> x == y - - A probability-1 algorithm to determine equality - Optional arguments: - strict -- if True, force each system to have the same variables, - parameters, by name; otherwise, allow the same number - of variables and parameters, but not necessarily share - names. e.g., - `F = PolynomialSystem('x**2 - 1') - G = PolynomialSystem('y**2 - 1') - F.equals(G, strict=True) == False - F.equals(G, strict=False) == True` - """ - if not isinstance(other, PolynomialSystem): - return False - # shape test - if self.shape != other.shape: - return False - - svars = list(self._variables) - ovars = list(other._variables) - spars = list(self._parameters) - opars = list(other._parameters) - spoly = self._polynomials - opoly = other._polynomials - salls = svars + spars - oalls = ovars + opars - - if strict and salls != oalls: - return False - - from random import random as rand - rsubs = [] - for vp in salls: - try: - real = rand()/rand() - imag = rand()/rand() - except ZeroDivisionError: - return self == other - rsubs.append(real + I*imag) - - ssubs = zip(salls, rsubs) - osubs = zip(oalls, rsubs) - - res = spoly.subs(ssubs) - opoly.subs(osubs) - return res.norm() < TOL - - def evalf(self, varpt, parpt=[]): - """ - """ - from functools import reduce - - variables = list(self._variables) - parameters = list(self._parameters) - polynomials = self._polynomials - if len(varpt) != len(variables): - msg = "point {0} is not in the domain of {1}".format(varpt, self) - raise ValueError(msg) - elif len(parpt) != len(parameters): - msg = "point {0} is not a valid parameter for {1}".format(parpt, self) - - if parpt: - parpt = reduce(lambda x,y: x.cat(y), parpt) - - varsubs = dict(zip(variables, varpt) + zip(parameters, parpt)) - - return AffinePoint(polynomials.evalf(subs=varsubs)) - - def homogenize(self, homvar): - """ - Homogenize the system - - If already homogeneous, return self - """ - polynomials = [p.as_poly(domain='CC') for p in self._polynomials] - variables = list(self._variables) - parameters = list(self._parameters) - - if self._homvar: - return self - - homvar = sympify(homvar) - homvars = [homvar] + variables - hompolys = [p.homogenize(homvar).as_expr() for p in polynomials] - return PolynomialSystem(hompolys, homvars, parameters, homvar) - - def jacobian(self): - """ - Returns the Jacobian, the polynomial system, and the variables, - all as symbolic matrices - """ - variables = self._variables - polynomials = self._polynomials - num_polynomials,num_variables = len(polynomials),len(variables) - jac = zeros(num_polynomials,num_variables) - for i in range(num_polynomials): - for j in range(num_variables): - jac[i,j] = polynomials[i].diff(variables[j]) - - return jac,polynomials,variables - - def matmul(self, other): - """ - x.matmul(y) <==> y*x - - (overriding __rmul__ gives strange behavior with spmatrix) - """ - res_polys = list(other * self._polynomials) - res = PolynomialSystem(res_polys) - - return res - - def fix_parameters(self, parsubs): - """ - Substitute parsubs in for parameters - """ - polynomials = self._polynomials - parameters = self._parameters - if type(parsubs) == dict: - toreplace = parsubs.keys() - replacements = parsubs.values() - elif len(parsubs) > len(parameters): - toreplace = parameters - replacements = parsubs[:len(parameters)] - elif len(parsubs) < len(parameters): - toreplace = parameters[:len(parsubs)] - replacements = parsubs - else: - toreplace = parameters - replacements = parsubs - - tosub = dict() - for p,q in zip(toreplace,replacements): - if not scalar_num(q) and len(q) > 1: - msg = 'cannot substitute {0}'.format(q) - raise TypeError(msg) - if isinstance(q, Point): - q = q.coordinates[0] - tosub[p] = q - polynomials = polynomials.subs(tosub) - parameters = set(parameters).difference(set(toreplace)) - if parameters: - parameters = sorted([str(p) for p in parameters]) - parameters = sympify(parameters) - self._parameters = parameters - self._polynomials = polynomials - - def pop(self, index=-1): - polynomials = list(self._polynomials) - variables = self._variables - parameters = self._parameters - - poly = polynomials.pop(index) - polynomials = spmatrix(polynomials) - if len(polynomials) > 0: - free_sym = polynomials.free_symbols - sympars = set(parameters).intersection(free_sym) - symvars = set(variables).intersection(free_sym) - - varstr = sorted([str(v) for v in symvars]) - parstr = sorted([str(p) for p in sympars]) - - variables = sympify(varstr) - parameters = sympify(parstr) - else: - variables = [] - parameters = [] - - self._polynomials = polynomials - self._variables = spmatrix(variables) - self._parameters = spmatrix(parameters) - - return poly - - def rank(self, tol=TOL): - """ - Return a numeric value, the rank of the Jacobian at - a 'generic' point. - """ - from random import random as rand - parameters = list(self._parameters) - variables = list(self._variables) - if parameters: - allvars = variables + parameters - else: - allvars = variables - - varsubs = zeros(len(allvars), 1) - # compute sufficiently generic complex points - for i in range(len(varsubs)): - # rand()/rand() can vary magnitude satisfactorily - try: - real = rand()/rand() - imag = rand()/rand() - except ZeroDivisionError: - # try again - return self.rank() - varsubs[i] = real + I*imag - - jac = self.jacobian()[0] - jac = jac.subs(zip(allvars, varsubs)) - - # allow user to specify tolerance (what is 'zero') - iszero = lambda x, tol=tol: True if abs(x) < tol else False - return jac.rank(iszero) - - def solve(self, start_params=None, final_params=None, start=None, usebertini=True): - """ - Solve the system. If non-square, return the NID - - If the system has parameters and you do not supply any parameters, - perform ab initio run and return solutions along with start parameters. - Otherwise if you supply parameters, just return the solutions. - """ - polynomials = self._polynomials - variables = self._variables - parameters = self._parameters - - if usebertini: - # parameter homotopy - if parameters: - if start_params and final_params: - solve_run = naglib.bertini.BertiniRun(self, - tracktype=naglib.bertini.BertiniRun.TZERODIM, - config={'ParameterHomotopy':2}, - start_parameters=start_params, - final_parameters=final_params, - start=start) - elif start_params or final_params: - msg = "specify both start parameters and final parameters or neither" - raise BertiniError(msg) - else: - solve_run = naglib.bertini.BertiniRun(self, - naglib.bertini.BertiniRun.TZERODIM, - config={'ParameterHomotopy':1}) - # numerical irreducible decomposition - elif len(variables) > len(polynomials) or self.rank() < len(polynomials): - solve_run = naglib.bertini.BertiniRun(self, naglib.bertini.BertiniRun.TPOSDIM) - # isolated solutions - else: - solve_run = naglib.bertini.BertiniRun(self, naglib.bertini.BertiniRun.TZERODIM) - - return solve_run.run() - else: - msg = "nothing to use yet but Bertini" - raise NotImplementedError(msg) - - def subs(self, *args, **kwargs): - """ - Return a new PolynomialSystem with subs applied to - each entry of 'polynomials' - - caution in using subs: - this will destroy any parameter/homvar information in the system - """ - polynomials = self._polynomials - psubs = polynomials.subs(*args, **kwargs) - ps = PolynomialSystem(psubs) - - return ps - - @property - def polynomials(self): - return self._polynomials - @property - def variables(self): - return self._variables - @property - def parameters(self): - return self._parameters - @property - def homvar(self): - # TODO: change this for multihomogeneous systems - if self._homvar: - return self._homvar[0] - else: - return self._homvar - @homvar.setter - def homvar(self, h): - if h is None: - self._homvar = spmatrix() - return - h = sympify(h) - if h not in self._variables: - msg = "homogenizing variable {0} not found in list of variables".format(h) - raise ValueError(msg) - - parameters = self._parameters - polynomials = self._polynomials - paramsubs = zip(parameters, [1 for p in parameters]) - for poly in polynomials: - p = poly.subs(paramsubs) - if p.is_number: - deg = 0 - else: - deg = p.as_poly(domain='CC').total_degree() - # now check if polynomial is homogeneous - terms = p.as_ordered_terms() - for t in terms: - if t.is_number and deg != 0: - msg = "polynomial {0} is not homogeneous".format(p) - raise NonHomogeneousException(msg) - elif t.is_number: - pass - elif t.as_poly(domain='CC').total_degree() != deg: - msg = "polynomial {0} is not homogeneous".format(p) - raise NonHomogeneousException(msg) - - if h in self._variables: - self._homvar = spmatrix([h]) - @property - def degree(self): - return self._degree - @property - def shape(self): - m = len(self._polynomials) - n = len(self._variables) - return (m,n) - -class LinearSlice(NAGObject): - """ - A linear system - - !!!Use this only for slicing!!! - """ - def __init__(self, coeffs, variables, homvar=None): - self._coeffs = spmatrix(coeffs) - self._variables = spmatrix(variables) - if homvar: - homvar = sympify(homvar) - if homvar not in variables: - msg = "homogenizing variable {0} not in variables".format(homvar) - raise ValueError(msg) - else: - self._homvar = homvar - else: - self._homvar = spmatrix() - - def __repr__(self): - """ - x.__repr__() <==> repr(x) - """ - coeffs = self._coeffs.n() - variables = self._variables - homvar = self._homvar - repstr = 'LinearSlice({0},{1},{2})'.format(coeffs, variables, homvar) - - return repstr - - def __str__(self): - """ - x.__str__() <==> str(x) - """ - repstr = '' - mat = self._coeffs * self._variables - strmat = [str(row) for row in mat] - maxlen = max([len(row) for row in strmat]) - for row in strmat: - repstr += '[' + ' '*(maxlen-len(row)) + row + ']\n' - - return repstr - - def dehomogenize(self): - """ - """ - homvar = self._homvar - if not homvar: - return self - - variables = list(self._variables) - coeffs = self._coeffs.copy() - - dex = variables.index(homvar) - variables.pop(dex) - dehom_coeffs = coeffs.col(dex) - coeffs.col_del(dex) - m,n = coeffs.shape - for i in range(m): - coeffs[i,:] = coeffs[i,:]/dehom_coeffs[i] - - return LinearSlice(coeffs, variables) - - @property - def codim(self): - mat = self._coeffs - m,n = mat.shape - return n - m - @property - def coeffs(self): - return self._coeffs - @property - def homvar(self): - return self._homvar - @property - def mat(self): - return self._coeffs * self._variables - @property - def rank(self, tol=TOL): - iszero = lambda x, tol=tol: True if abs(x) < tol else False - return self._coeffs.rank(iszerofunc=iszero) - @property - def shape(self): - return self._coeffs.shape - @property - def variables(self): - return self._variables diff --git a/naglib/core/base.py b/naglib/core/base.py deleted file mode 100644 index 0485d88..0000000 --- a/naglib/core/base.py +++ /dev/null @@ -1,482 +0,0 @@ -import numbers - -from naglib.exceptions import ExitSpaceError, AffineInfinityException -from naglib.constants import TOL - - -def is_scalar(z): - """ - Determine if z is a scalar type for purposes of multiplication - """ - - return isinstance(z, numbers.Number) - - -class NAGObject(object): - """ - A meta class. Nothing here (yet) - """ - pass - - -class Point(NAGObject): - """ - A point in affine or projective space - """ - - def __init__(self, coordinates): - """ - Initialize the Point object - """ - self._coordinates = Matrix(coordinates) - - def __add__(self, other): - """ - x.__add__(y) <==> x + y - """ - cls = self.__class__ - if not isinstance(other, cls): - t = type(other) - msg = "unsupported operand type(s) for +: '{0}' and '{1}'".format(cls, t) - raise TypeError(msg) - - sco = self._coordinates - oco = other._coordinates - - if len(sco) != len(oco): - msg = "dimension mismatch" - raise ShapeError(msg) - - return cls(list(sco + oco)) - - def __sub__(self, other): - """ - x.__sub__(y) <==> x - y - """ - cls = self.__class__ - if not isinstance(other, cls): - t = type(other) - msg = "unsupported operand type(s) for -: '{0}' and '{1}'".format(cls, t) - raise TypeError(msg) - - return self + -other - - def __neg__(self): - """ - x.__neg__() <==> -x - """ - cls = self.__class__ - coordinates = self._coordinates - return cls(list(-coordinates)) - - def __mul__(self, other): - """ - x.__mul__(y) <==> x*y - """ - cls = self.__class__ - if not is_scalar(other): - t = type(other) - msg = "unsupported operand type(s) for *: '{0}' and '{1}'".format(cls, t) - raise TypeError(msg) - else: - coordinates = self._coordinates - return cls(other * coordinates) - - def __rmul__(self, other): - """ - x.__rmul__(y) <==> y*x - """ - cls = self.__class__ - if not is_scalar(other): - t = type(other) - msg = "unsupported operand type(s) for *: '{0}' and '{1}'".format(t, cls) - raise TypeError(msg) - else: - return self * other - - def __div__(self, other): - """ - x.__div__(y) <==> x/y - """ - return self.__truediv__(other) - - def __truediv__(self, other): - """ - x.__truediv__(y) <==> x/y - """ - cls = self.__class__ - if not is_scalar(other): - t = type(other) - msg = "unsupported operand type(s) for /: '{0}' and '{1}'".format(cls, t) - raise TypeError(msg) - else: - if other == 0: - msg = "division by zero" - raise ZeroDivisionError(msg) - coordinates = self._coordinates - return cls((1.0/other) * coordinates) - - def __eq__(self, other): - """ - x.__eq__(y) <==> x == y - """ - cls = self.__class__ - if not isinstance(other, cls): - return False - - sco = self._coordinates - oco = other._coordinates - - return (sco == oco) - - def __len__(self): - """ - x.__len__() <==> len(x) - """ - coordinates = self._coordinates - return len(coordinates) - - def __getitem__(self, key): - """ - x.__getitem__(y) <==> x[y] - """ - coordinates = self._coordinates - return coordinates[key] - - def __setitem__(self, key, value): - """ - x.__setitem__(y, z) <==> x[y] = z - """ - if not is_scalar(value): - msg = "must assign a number" - raise TypeError(msg) - - coordinates = self._coordinates - coordinates[key] = sympify(value) - - def __setslice__(self, i, j, sequence): - """ - x.__setslice__(i,j,sequence) <==> x[i:j] = sequence - """ - coordinates = self._coordinates - - sequence = sympify(list(sequence)) - for s in sequence: - if not is_scalar(s): - msg = "must assign a number" - raise TypeError(msg) - - cocopy = coordinates[:] - cocopy[i:j] = sequence - self._coordinates = Matrix(cocopy) - - def cat(self, other): - """ - concatenate other onto self - """ - cls = self.__class__ - if not isinstance(other, cls): - t = type(other) - msg = "I don't know how to concatenate type {0} to type {1}".format(t, cls) - raise TypeError(msg) - scoords = list(self._coordinates) - ocoords = list(other._coordinates) - - return cls(scoords + ocoords) - - def float(self, prec=None): - cls = self.__class__ - coordinates = self._coordinates - newcoords = [] - for c in coordinates: - real,imag = c.as_real_imag() - if prec: - real = sympy.Float(real, prec) - imag = sympy.Float(imag, prec) - else: - real = sympy.Float(real) - imag = sympy.Float(imag) - newcoords.append(real + sympy.I*imag) - - return cls(newcoords) - - def insert(self, index, item): - if not is_scalar(item): - msg = "only takes scalar number types" - raise TypeError(msg) - coordinates = list(self._coordinates) - coordinates.insert(index, item) - self._coordinates = Matrix(coordinates) - - def is_zero(self, tol=TOL*10): - coordinates = self._coordinates - summa = sum([abs(c)**2 for c in coordinates])**0.5 - return summa < tol - - def normalized(self): - """ - Returns the normalized version of self - """ - coordinates = self._coordinates - return self.__class__(coordinates.normalized()) - - def pop(self, index=-1): - coordinates = list(self._coordinates) - popped = coordinates.pop(index) - self._coordinates = Matrix(coordinates) - - return popped - - def rational(self): - """ - Returns a rational approximation of self - """ - cls = self.__class__ - coordinates = self._coordinates - newcoords = [] - for c in coordinates: - real,imag = c.as_real_imag() - real = Rational(real) - imag = Rational(imag) - newcoords.append(real + sympy.I*imag) - - return cls(newcoords) - - def is_real(self, tol=1e-13): - coordinates = self._coordinates - return coordinates.as_real_imag()[1].norm() < tol - - @property - def coordinates(self): - return self._coordinates - - -class AffinePoint(Point): - """ - Point object living in affine space - """ - def __init__(self, coordinates): - super(AffinePoint, self).__init__(coordinates) - - def __repr__(self): - coordinates = [str(c.n()) for c in self._coordinates] - repstr = 'AffinePoint([' - if len(coordinates) > 6: - repstr += ', '.join(coordinates[:3] + ['...'] + coordinates[-3:]) + '])' - else: - repstr = 'AffinePoint({0})'.format(', '.join(coordinates)) - - return repstr - - def __str__(self): - """ - x.__str__ <==> str(x) - """ - coordinates = self._coordinates - repstr = '[' + ', '.join([str(c) for c in coordinates]) + ']' - - return repstr - - def __abs__(self): - """ - x.__abs__ <==> abs(x) - """ - coordinates = self._coordinates - return coordinates.norm() - - def homogenize(self): - """ - """ - homcoordinates = [1] + list(self._coordinates) - - return ProjectivePoint(homcoordinates) - - def norm(self, ord=None): - """ - Return the norm of AffinePoint - Acceptable values: - None <==> 2-norm - inf <==> max(abs(x)) - -inf <==> min(abs(x)) - n <==> sum(abs(x)**n)**(1./n) - """ - coordinates = self._coordinates - return coordinates.norm(ord) - - @property - def dim(self): - return len(self._coordinates) - -class ProjectivePoint(Point): - """ - Point object living in affine space - """ - def __init__(self, coordinates, tol=TOL*10): - super(ProjectivePoint, self).__init__(coordinates) - - if self.is_zero(tol): - corstr = '[' + ' : '.join([str(c) for c in self._coordinates]) + ']' - msg = "{0} is not in projective space".format(corstr) - raise ExitSpaceError(msg) - self._dim = len(self._coordinates) - 1 - self._tol = tol - - def __repr__(self): - coordinates = [str(c.n()) for c in self._coordinates] - repstr = 'ProjectivePoint([' - if len(coordinates) > 6: - repstr += ', '.join(coordinates[:3] + ['...'] + coordinates[-3:]) + '])' - else: - repstr = 'ProjectivePoint({0})'.format(', '.join(coordinates)) - - return repstr - - def __str__(self): - """ - x.__str__ <==> str(x) - """ - coordinates = self._coordinates - repstr = '[' + ' : '.join([str(c) for c in coordinates]) + ']' - - return repstr - - def __add__(self, other): - """ - x.__add__(y) <==> x + y - """ - res = super(ProjectivePoint, self).__add__(other) - if res.is_zero(self._tol): - msg = 'you have left projective space' - raise ExitSpaceError(msg) - - return res - - def __sub__(self, other): - """ - x.__sub__(y) <==> x - y - """ - res = super(ProjectivePoint, self).__sub__(other) - if res.is_zero(self._tol): - msg = 'you have left projective space' - raise ExitSpaceError(msg) - - return res - - def __mul__(self, other): - """ - x.__mul__(y) <==> x*y - """ - res = super(ProjectivePoint, self).__mul__(other) - if res.is_zero(self._tol): - msg = 'you have left projective space' - raise ExitSpaceError(msg) - - return res - - def __rmul__(self, other): - """ - x.__rmul__(y) <==> y*x - """ - res = super(ProjectivePoint, self).__rmul__(other) - if res.is_zero(self._tol): - msg = 'you have left projective space' - raise ExitSpaceError(msg) - - def __div__(self, other): - """ - x.__div__(y) <==> x/y - """ - res = super(ProjectivePoint, self).__div__(other) - if res.is_zero(self._tol): - msg = 'you have left projective space' - raise ExitSpaceError(msg) - - return res - - def __truediv__(self, other): - """ - x.__truediv__(y) <==> x/y - """ - res = super(ProjectivePoint, self).__truediv__(other) - if res.is_zero(self._tol): - msg = 'you have left projective space' - raise ExitSpaceError(msg) - - return res - - def __eq__(self, other): - """ - x.__eq__(u=y) <==> x == y - """ - if not isinstance(other, ProjectivePoint): - return False - - # (x0, ..., xn) == (y0, ..., yn) if there exists c s.t. - # (x0, ..., xn) == c(y0, ..., yn) - sho = self.canonical() - oho = other.canonical() - sco = sho._coordinates - oco = oho._coordinates - - return sco == oco - - def __setitem__(self, key, value): - """ - x.__setitem__(y, z) <==> x[y] = z - """ - coordinates = self._coordinates.copy() - super(ProjectivePoint, self).__setitem__(key, value) - if self.is_zero(self._tol): - self._coordinates = coordinates - msg = 'you have left projective space' - raise ExitSpaceError(msg) - - def __setslice__(self, i, j, sequence): - """ - x.__setitem__(y, z) <==> x[y] = z - """ - coordinates = self._coordinates.copy() - super(ProjectivePoint, self).__setslice__(i, j, sequence) - if self.is_zero(self._tol): - self._coordinates = coordinates - msg = 'you have left projective space' - raise ExitSpaceError(msg) - - def at_infinity(self, tol=TOL): - coordinates = self._coordinates - c0 = coordinates[0] - div_coord = [c0/c for c in coordinates[1:]] - return sum([abs(c)**2 for c in div_coord])**(0.5) < tol - - def canonical(self): - """ - Return ProjectivePoint with coordinates rescaled - """ - coordinates = self._coordinates - nz = 0 - while abs(coordinates[nz]) < TOL and nz < len(coordinates): - nz += 1 - c1 = coordinates[nz] - - return ProjectivePoint(coordinates/c1) - - def dehomogenize(self): - """ - Return Affine Point, if not at at infinity - """ - if not self.at_infinity(): - coordinates = self._coordinates - return AffinePoint([c/coordinates[0] for c in coordinates[1:]]) - else: - msg = "cannot create affine point from {0}; point is at infinity".format(self) - raise AffineInfinityException(msg) - - @property - def dim(self): - return len(self._coordinates)-1 - @property - def tol(self): - return self._tol - @tol.setter - def tol(self, t): - self._tol = t diff --git a/naglib/core/geometry.py b/naglib/core/geometry.py deleted file mode 100644 index 1a1eb69..0000000 --- a/naglib/core/geometry.py +++ /dev/null @@ -1,208 +0,0 @@ -from __future__ import print_function - -from sympy import Matrix - -from naglib.bertini.sysutils import BertiniRun -from naglib.exceptions import BertiniError -from naglib.core.base import NAGObject - -class IrreducibleComponent(NAGObject): - """ - An irreducible component of an algebraic set - """ - def __init__(self, witness_set, codim, component_id, **kwargs): - """ - Initialize the IrreducibleComponent object. - - Keyword arguments: - witness_set -- WitnessSet, the witness set describing this component - codim -- int, the codimension of the component - component_id -- int, the component number for this dimension - - Optional keyword arguments: - """ - self._witness_set = witness_set - self._codim = codim - self._component_id = component_id - self._degree = len(witness_set.witness_points) - - # optional keyword arguments - kkeys = kwargs.keys() - - if 'randomization_matrix' in kkeys: - self._randomization_matrix = kwargs['randomization_matrix'] - else: - self._randomization_matrix = Matrix([]) - - if 'homogenization_matrix' in kkeys: - self._homogenization_matrix = kwargs['homogenization_matrix'] - else: - self._homogenization_matrix = Matrix([]) - - if 'homogenization_vector' in kkeys: - self._homogenization_vector = kwargs['homogenization_vector'] - else: - self._homogenization_vector = Matrix([]) - - if 'homogenization_variable' in kkeys: - self._homogenization_variable = kwargs['homogenization_variable'] - else: - self._homogenization_variable = None - - if 'patch_coefficients' in kkeys: - self._patch_coefficients = kwargs['patch_coefficients'] - else: - self._patch_coefficients = Matrix([]) - - def __str__(self): - """ - x.__str__() <==> str(x) - """ - codim = self._codim - cid = self._component_id - deg = self._degree - return '{0}-dimensional irreducible component ({2}) of degree {1}'.format(codim,deg,cid) - - def __repr__(self): - """ - x.__repr__() <==> repr(x) - """ - codim = self._codim - cid = self._component_id - wst = self._witness_set - repstr = 'IrreducibleComponent({0},{1},{2})'.format(repr(wst),codim,cid) - return repstr - - def __eq__(self, other): - """ - x.__eq__(y) <==> x == y - """ - if type(other) != IrreducibleComponent: - return False - - sp = self.sample(1) - op = other.sample(1) - - sco = self.contains(op) - ocs = other.contains(sp) - - return sco and ocs - - def _construct_witness_data(self): - codim = self._codim - wpoints = self.witness_set.witness_points - hslice = self.witness_set.homogeneous_slice.coeffs - if not hslice: - hslice = self.witness_set.linear_slice.coeffs - homogenization_matrix = self._homogenization_matrix - homogenization_variable = self._homogenization_variable - homogenization_vector = self._homogenization_vector - patch_coefficients = self._patch_coefficients - randomization_matrix = self._randomization_matrix - - wd = { - 'codim':codim, - 'points':[], - 'A':randomization_matrix, - 'W':homogenization_matrix, - 'homVarConst':homogenization_variable, - 'H':homogenization_vector, - 'p':patch_coefficients, - 'slice':hslice - } - - for p in wpoints: - if p.homogeneous_coordinates: - coordinates = p.homogeneous_coordinates - else: - coordinates = p.coordinates - wd['points'].append({ - 'precision':p.precision, - 'coordinates':coordinates, - 'last approximation':p.last_approximation.coordinates, - 'condition number':p.condition_number, - 'corank':p.corank, - 'smallest nonzero':p.smallest_nonzero, - 'largest zero':p.largest_zero, - 'type':p.point_type, - 'multiplicity':p.multiplicity, - 'component number':0, - 'deflations':p.deflations - }) - - return [wd] - - def contains(self, other): - """ - Return True if self contains other - """ - if type(other) not in (list, tuple): - msg = "cannot understand data type" - raise TypeError(msg) - - system = self._witness_set.system - test_run = BertiniRun(system, - tracktype=BertiniRun.TMEMTEST, - component=self, - start=other) - return test_run.run() - - def sample(self, numpoints=1, usebertini=True): - """ - Sample points from self - """ - if numpoints < 1: - msg = "sample at least one point" - raise BertiniError(msg) - system = self.witness_set.system - - points = None - if usebertini: - sample_run = BertiniRun(system, BertiniRun.TSAMPLE, sample=numpoints, component=self) - points = sample_run.run() - else: - msg = "nothing to use yet but Bertini" - raise NotImplementedError(msg) - - return points - - @property - def codim(self): - return self._codim - @property - def component_id(self): - return self._component_id - @property - def degree(self): - return self._degree - @property - def dim(self): - variables = self.system.variables - return len(variables) - self._codim - @property - def homogenization_matrix(self): - return self._homogenization_matrix - @property - def homogenization_variable(self): - return self._homogenization_variable - @property - def homogenization_vector(self): - return self._homogenization_vector - @property - def is_projective(self): - return not not self._homogenization_variable - @property - def patch_coefficients(self): - return self._patch_coefficients - @property - def randomization_matrix(self): - return self._randomization_matrix - @property - def system(self): - return self._witness_set.system - @property - def witness_data(self): - return self._witness_set._witness_data - @property - def witness_set(self): - return self._witness_set \ No newline at end of file diff --git a/naglib/core/witnessdata.py b/naglib/core/witnessdata.py deleted file mode 100644 index 80bc1f1..0000000 --- a/naglib/core/witnessdata.py +++ /dev/null @@ -1,364 +0,0 @@ -from sympy import I, Float, Rational, Matrix - -from naglib.exceptions import WitnessDataException -from naglib.core.base import NAGObject, Point, AffinePoint, ProjectivePoint - - -class WitnessPoint(Point): - """ - A single witness point for an algebraic set - """ - def __init__(self, coordinates, component_id, is_projective=False, **kwargs): - """ - Initialize the WitnessPoint object. - - Keyword arguments: - point -- AffinePoint or ProjectivePoint - component_id -- int, the id of the component to which self belongs - """ - super(WitnessPoint, self).__init__(coordinates) - self._component_id = component_id - self._is_projective = is_projective - if isinstance(coordinates, AffinePoint): - self._is_projective = False - elif isinstance(coordinates, ProjectivePoint): - self._is_projective = True - - kkeys = kwargs.keys() - - if 'corank' in kkeys: - self._corank = kwargs['corank'] - else: - self._corank = -1 - - if 'condition_number' in kkeys: - self._condition_number = kwargs['condition_number'] - else: - self._condition_number = 0 - - if 'smallest_nonzero' in kkeys: - self._smallest_nonzero = kwargs['smallest_nonzero'] - else: - self._smallest_nonzero = 0 - - if 'largest_zero' in kkeys: - self._largest_zero = kwargs['largest_zero'] - else: - self._largest_zero = 0 - - if 'point_type' in kkeys: - self._point_type = kwargs['point_type'] - else: - self._point_type = 0 - - if 'multiplicity' in kkeys: - self._multiplicity = kwargs['multiplicity'] - else: - self._multiplicity = 1 - - if 'deflations' in kkeys: - self._deflations = kwargs['deflations'] - else: - self._deflations = 0 - - if 'precision' in kkeys: - self._precision = kwargs['precision'] - else: - self._precision = 0 - - if 'last_approximation' in kkeys: - self._last_approximation = kwargs['last_approximation'] - else: - self._last_approximation = Matrix([]) - - if 'homogeneous_coordinates' in kkeys: - self._homogeneous_coordinates = kwargs['homogeneous_coordinates'] - else: - self._homogeneous_coordinates = Matrix([]) - - # TODO: sanity check projective point - - def __repr__(self): - """ - x.__repr__() <==> repr(x) - """ - coordinates = [str(c.n()) for c in self._coordinates] - component_id = self._component_id - is_projective = self._is_projective - - if is_projective: - repstr = 'ProjectivePoint([' - if len(coordinates) > 6: - repstr += ', '.join(coordinates[:3] + ['...'] + coordinates[-3:]) + '])' - else: - repstr = 'ProjectivePoint({0})'.format(', '.join(coordinates)) - else: - repstr = 'AffinePoint([' - if len(coordinates) > 6: - repstr += ', '.join(coordinates[:3] + ['...'] + coordinates[-3:]) + '])' - else: - repstr = 'AffinePoint({0})'.format(', '.join(coordinates)) - - repstr = 'WitnessPoint({0},{1})'.format(repstr, component_id) - - return repstr - - def __str__(self): - """ - x.__str__() <==> str(x) - """ - coordinates = self._coordinates - is_projective = self._is_projective - - if is_projective: - repstr = '[' + ' : '.join([str(c) for c in coordinates]) + ']' - else: - repstr = '[' + ', '.join([str(c) for c in coordinates]) + ']' - - return repstr - - def as_point(self): - coordinates = self._coordinates - is_projective = self._is_projective - if is_projective: - return ProjectivePoint(coordinates) - else: - return AffinePoint(coordinates) - - def dehomogenize(self): - """ - Dehomogenize the witness point - - Returns a new WitnessPoint object - """ - cls = self.__class__ - component_id = self._component_id - coordinates = self._coordinates - is_projective = self._is_projective - - if is_projective: - point = ProjectivePoint(coordinates) - else: - point = AffinePoint(coordinates) - - deh = cls(point, component_id) - deh._is_projective = self._is_projective - deh._condition_number = self._condition_number - deh._corank = self._corank - deh._deflations = self._deflations - deh._last_approximation = self._last_approximation - deh._largest_zero = self._largest_zero - deh._multiplicity = self._multiplicity - deh._point_type = self._point_type - deh._precision = self._precision - deh._smallest_nonzero = self._smallest_nonzero - - return deh - - def float(self, prec=None): - cls = self.__class__ - component_id = self._component_id - coordinates = self._coordinates - newcoords = [] - for c in coordinates: - real,imag = c.as_real_imag() - if prec: - real = Float(real, prec) - imag = Float(imag, prec) - else: - real = Float(real) - imag = Float(imag) - newcoords.append(real + I*imag) - flo = cls(coordinates, component_id) - - flo._is_projective = self._is_projective - flo._condition_number = self._condition_number - flo._corank = self._corank - flo._deflations = self._deflations - flo._last_approximation = self._last_approximation.float() - flo._largest_zero = self._largest_zero - flo._multiplicity = self._multiplicity - flo._point_type = self._point_type - if prec and prec <= self._precision: - flo._precision = prec - else: - flo._precision = self._precision - flo._smallest_nonzero = self._smallest_nonzero - - return flo - - def rational(self): - """ - Returns a rational approximation of self - """ - cls = self.__class__ - component_id = self._component_id - coordinates = self._coordinates - newcoords = [] - for c in coordinates: - real,imag = c.as_real_imag() - real = Rational(real) - imag = Rational(imag) - newcoords.append(real + I*imag) - rat = cls(newcoords, component_id) - - rat._is_projective = self._is_projective - rat._condition_number = self._condition_number - rat._corank = self._corank - rat._deflations = self._deflations - rat._last_approximation = self._last_approximation - rat._largest_zero = self._largest_zero - rat._multiplicity = self._multiplicity - rat._point_type = self._point_type - rat._precision = self._precision - rat._smallest_nonzero = self._smallest_nonzero - - return rat - - @property - def condition_number(self): - """ - The condition number of the Jacobian at this point - """ - return self._condition_number - - @property - def corank(self): - """ - The corank of the Jacobian at this point - """ - return self._corank - - @property - def component_id(self): - return self._component_id - - @property - def deflations(self): - """ - The number of deflations this point required - """ - return self._deflations - - @property - def homogeneous_coordinates(self): - """ - The homogeneous coordinates of the witness point - """ - return self._homogeneous_coordinates - - @property - def last_approximation(self): - coordinates = self._last_approximation - is_projective = self._is_projective - if is_projective: - return ProjectivePoint(coordinates) - else: - return AffinePoint(coordinates) - - @property - def largest_zero(self): - """ - The largest `zero' singular value of the Jacobian at this point - """ - return self._largest_zero - - @property - def multiplicity(self): - """ - The multiplicity of this point with respect to the system - """ - return self._multiplicity - - @property - def point_type(self): - return self._point_type - - @property - def precision(self): - """ - The numerical precision required by this point - """ - return self._precision - - @property - def smallest_nonzero(self): - """ - The smallest nonzero singular value of the Jacobian at this point - """ - return self._smallest_nonzero - -class WitnessSet(NAGObject): - """ - A witness set for a component - """ - def __init__(self, system, lslice, witness_points, witness_data, **kwargs): - """Initialize the WitnessSet - - Keyword arguments: - system -- PolynomialSystem, system on which all the points vanish - slice -- LinearSystem, system defining a generic linear space - witness_points -- iterable of WitnessPoint objects, witness point set, V(f) \cap V(L) - """ - self._system = system - self._slice = lslice - self._witness_data = witness_data - try: - self._witness_points = list(witness_points) - except TypeError: - self._witness_points = [witness_points] - - wp = self._witness_points[0] - self._component_id = wp._component_id - for w in self._witness_points: - if w._component_id != self._component_id: - msg = 'WitnessPoint {0} and WitnessPoint {1} do not lie on the same component'.format(wp, w) - raise WitnessDataException(msg) - - kkeys = kwargs.keys() - - if 'homogeneous_slice' in kkeys: - self._homogeneous_slice = kwargs['homogeneous_slice'] - else: - self._homogeneous_slice = None - - def __repr__(self): - """ - x.__repr__() <==> repr(x) - """ - sy = self._system - sl = self._slice - wp = self._witness_points - repstr = 'WitnessSet({0},{1},{2})'.format(repr(sy), repr(sl), repr(wp)) - - return repstr - - def __str__(self): - """ - x.__str__() <==> str(x) - """ - wp = self._witness_points - repstr = '{' + ', '.join([str(p) for p in wp]) + '}' - - return repstr - - - @property - def homogeneous_slice(self): - return self._homogeneous_slice - - @property - def linear_slice(self): - return self._slice - - @property - def system(self): - return self._system - - @property - def witness_data(self): - return self._witness_data - - @property - def witness_points(self): - return self._witness_points \ No newline at end of file diff --git a/naglib/exceptions.py b/naglib/exceptions.py index 9add824..2e25de9 100644 --- a/naglib/exceptions.py +++ b/naglib/exceptions.py @@ -7,13 +7,15 @@ def __init__(self, message): def __str__(self): return self.message - + + class AffineInfinityException(NAGlibBaseException): """ """ def __init__(self, message): super(AffineInfinityException, self).__init__(message) - + + class BertiniError(Exception): """ BertiniError @@ -22,23 +24,15 @@ class BertiniError(Exception): """ def __init__(self, message): super(BertiniError, self).__init__(message) - + + class ExitSpaceError(NAGlibBaseException): """ """ def __init__(self, message): super(ExitSpaceError, self).__init__(message) -class NoBertiniException(NAGlibBaseException): - """ - NoBertiniException - - Raise NoBertiniException when Bertini can't be located on the system - """ - def __init__(self): - message = "you don't seem to have Bertini installed anywhere I can find it" - super(NoBertiniException, self).__init__(message) - + class NonPolynomialException(NAGlibBaseException): """ NonPolynomialException @@ -48,7 +42,8 @@ class NonPolynomialException(NAGlibBaseException): """ def __init__(self, message): super(NonPolynomialException, self).__init__(message) - + + class NonHomogeneousException(NAGlibBaseException): """ NonHomogeneousException @@ -58,13 +53,15 @@ class NonHomogeneousException(NAGlibBaseException): """ def __init__(self, message): super(NonHomogeneousException, self).__init__(message) - + + class UnclassifiedException(NAGlibBaseException): """ """ def __init__(self, message): super(UnclassifiedException, self).__init__(message) - + + class WitnessDataException(NAGlibBaseException): """ """ diff --git a/naglib/misc.py b/naglib/misc.py deleted file mode 100644 index 722ce34..0000000 --- a/naglib/misc.py +++ /dev/null @@ -1,11 +0,0 @@ -def dps(s): - #return max(DPS, len(s)) - s = str(s) if not isinstance(s, str) else s - return len(s) - - -def striplines(lines, nonempty=True): - if nonempty: - return [l.strip() for l in lines if l != '\n'] - else: - return [l.strip() for l in lines] \ No newline at end of file diff --git a/naglib/system.py b/naglib/system.py deleted file mode 100644 index ca402af..0000000 --- a/naglib/system.py +++ /dev/null @@ -1,46 +0,0 @@ -import multiprocessing -import subprocess -import sys - -def __os(): - if sys.platform.startswith("win"): - return "WINDOWS" - elif sys.platform.startswith("cygwin"): - return "CYGWIN" - elif sys.platform.startswith("linux"): - return "LINUX" - elif sys.platform.startswith("darwin"): - return "OSX" - -def __which(exe): - platform = __os() - if platform == "WINDOWS": - cmd = "where.exe" - else: - cmd = "which" - - try: - path = subprocess.check_output([cmd, exe], universal_newlines=True).strip() - except subprocess.CalledProcessError: - path = "" - - return path - -def proc_err_output(output): - lines = output.split("\n") - idx = None - for l in lines: - if l.startswith("ERROR"): - idx = lines.index(l) - if idx is None: - return output - else: - errline = lines[idx] - # strip "ERROR: " - lines[idx] = errline[errline.index(" ")+1:] - # strip "Bertini will now exit due to this error" - return "\n".join(lines[idx:-1]) - -BERTINI = __which("bertini") -MPIRUN = __which("mpirun") -PCOUNT = multiprocessing.cpu_count() diff --git a/test/context.py b/test/context.py index e27de3e..b7cd8d4 100644 --- a/test/context.py +++ b/test/context.py @@ -4,3 +4,6 @@ print(__file__) BASEDIR = op.abspath(op.join(op.dirname(__file__), "..")) sys.path.insert(0, BASEDIR) + +ZERO_DIM_BASE = op.join(BASEDIR, "test", "data", "zero_dim") +POS_DIM_BASE = op.join(BASEDIR, "test", "data", "pos_dim") diff --git a/test/data/zero_dim/parameter_homotopy/input b/test/data/zero_dim/parameter_homotopy/input new file mode 100644 index 0000000..fdec76c --- /dev/null +++ b/test/data/zero_dim/parameter_homotopy/input @@ -0,0 +1,10 @@ +CONFIG +parameterhomotopy:1; +randomseed:10191; +END; +INPUT +variable_group x; +parameter a0,a1,a2,a3,a4,a5,a6; +function f; +f = a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6))))); +END; diff --git a/test/test_io.py b/test/test_io.py new file mode 100644 index 0000000..775173b --- /dev/null +++ b/test/test_io.py @@ -0,0 +1,78 @@ +from context import op, ZERO_DIM_BASE, POS_DIM_BASE + +from collections import OrderedDict + +import numpy as np + +from naglib.bertini.io import read_input_file, read_points_file +from naglib.bertini.input_file import BertiniInput, BertiniConfig + + +def is_empty(x): + return len(x) == 0 + + +def test_read_input1(): + config, inputs, misclines = read_input_file(op.join(POS_DIM_BASE, "sampling", "input")) + + assert isinstance(config, BertiniConfig) + assert config.tracktype == 2 + assert config.mptype == 2 + assert config.precision == 96 + assert config.coeffbound == 1000 + assert config.degreebound == 5 + assert config.ampmaxprec == 1024 + assert config.parameterhomotopy == 0 + assert config.randomseed == 0 + + assert isinstance(inputs, BertiniInput) + assert is_empty(inputs.constant) + assert is_empty(inputs.variable) + assert is_empty(inputs.hom_variable_group) + assert is_empty(inputs.subfunction) + assert is_empty(inputs.parameter) + assert is_empty(inputs.random) + assert is_empty(inputs.random_real) + assert is_empty(inputs.pathvariable) + assert inputs.ndims == 3 + assert len(inputs.variable_group) == 1 + assert inputs.variable_group[0] == ["x", "y", "z"] + assert len(inputs.function) == 3 + assert inputs.function["f1"] == "(y-x^2)*(x^2+y^2+z^2-1)*(x-0.5)" + assert inputs.function["f2"] == "(z-x^3)*(x^2+y^2+z^2-1)*(y-0.5)" + assert inputs.function["f3"] == "(y-x^2)*(z-x^3)*(x^2+y^2+z^2-1)*(z-0.5)" + + assert isinstance(misclines, list) and len(misclines) == 0 + + +def test_read_input2(): + config, inputs, misclines = read_input_file(op.join(ZERO_DIM_BASE, "parameterhomotopy", "input")) + + assert isinstance(config, BertiniConfig) + assert config.tracktype == 0 + assert config.mptype == 2 + assert config.precision == 96 + assert config.coeffbound == 1000 + assert config.degreebound == 5 + assert config.ampmaxprec == 1024 + assert config.parameterhomotopy == 0 + assert config.randomseed == 10191 + + assert isinstance(inputs, BertiniInput) + assert is_empty(inputs.constant) + assert is_empty(inputs.variable) + assert is_empty(inputs.hom_variable_group) + assert is_empty(inputs.subfunction) + assert is_empty(inputs.parameter) + assert is_empty(inputs.random) + assert is_empty(inputs.random_real) + assert is_empty(inputs.pathvariable) + assert inputs.ndims == 3 + assert len(inputs.variable_group) == 1 + assert inputs.variable_group[0] == ["x", "y", "z"] + assert len(inputs.function) == 3 + assert inputs.function["f1"] == "(y-x^2)*(x^2+y^2+z^2-1)*(x-0.5)" + assert inputs.function["f2"] == "(z-x^3)*(x^2+y^2+z^2-1)*(y-0.5)" + assert inputs.function["f3"] == "(y-x^2)*(z-x^3)*(x^2+y^2+z^2-1)*(z-0.5)" + + assert isinstance(misclines, list) and len(misclines) == 0 diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index be0a55f..c6d95cc 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -1,20 +1,42 @@ -from context import op, BASEDIR +from context import op, ZERO_DIM_BASE from collections import OrderedDict +import numpy as np + +from naglib.bertini.io import read_points_file from naglib.bertini.run import BertiniRun from naglib.bertini.input_file import BertiniInput, BertiniConfig -def test_ab_initio(): +class TestParameterHomotopy(): + def setup_method(self): + self.working_dir = op.join(ZERO_DIM_BASE, "parameter_homotopy") + self.inputs = BertiniInput(variable_group=[["x"]], + parameter=OrderedDict((f"a{i}", None) for i in range(7)), + function=OrderedDict(f="a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))")) + + self.config = BertiniConfig(parameterhomotopy=1, randomseed=10191) + + brun = BertiniRun(self.config, self.inputs) + self.ab_initio_result = brun.run(dirname=self.working_dir) + + def test_ab_initio(self): + finite_solutions = np.array([[0.78101599+0.18185757j, 0.33253178+1.4856318j, + -0.71413828+1.01669647j, -0.53917013-0.04838107j, + -0.65402653-0.7627159j , 0.43428293-0.98042348j]]) + assert np.linalg.norm(finite_solutions - self.ab_initio_result.finite_solutions) < 1e-8 + + # def test_parameter_homotopy2(self): + + + +def test_parameter_homotopy2(): inputs = BertiniInput(variable_group=[["x"]], parameter=OrderedDict((f"a{i}", None) for i in range(7)), function=OrderedDict(f="a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))")) - config = BertiniConfig(parameterhomotopy=1) + start_parameters = read_points_file(op.join(ZERO_DIM_BASE, "parameter_homotopy", "start_parameters")) + start_points = read_points_file(op.join(ZERO_DIM_BASE, "parameter_homotopy", "start")) + config = BertiniConfig(parameterhomotopy=2, randomseed=10191) brun = BertiniRun(config, inputs) - result = brun.run(dirname=op.join(BASEDIR, "test", "param-htpy")) - - assert result.finite_solutions.shape == (1, 6) - print(result.start_parameters) - diff --git a/test/test_write_input.py b/test/test_write_input.py deleted file mode 100644 index b7cfd3d..0000000 --- a/test/test_write_input.py +++ /dev/null @@ -1,7 +0,0 @@ -# -*- coding: utf-8 -*- - -from context import op, BASEDIR - -from collections import deque, OrderedDict - - From d85ae3bc0f5f6980af5b08c6aa8cd07b9d0be1a4 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Thu, 27 Jun 2019 06:42:20 -0400 Subject: [PATCH 11/25] parameter homotopy 1 and 2, recover config and input after run --- .gitignore | 2 + naglib/bertini/input_file.py | 10 +- naglib/bertini/io.py | 185 +++++++++++++++++++++----------- naglib/bertini/run.py | 24 ++--- test/test_io.py | 88 ++++++++------- test/test_parameter_homotopy.py | 29 ++--- 6 files changed, 199 insertions(+), 139 deletions(-) diff --git a/.gitignore b/.gitignore index 2c2e317..0a293cd 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,9 @@ __pycache__ # test output test/data/zero_dim/**/failed_paths +test/data/zero_dim/**/final_parameters test/data/zero_dim/**/finite_solutions +test/data/zero_dim/**/function test/data/zero_dim/**/main_data test/data/zero_dim/**/midpath_data test/data/zero_dim/**/nonsingular_solutions diff --git a/naglib/bertini/input_file.py b/naglib/bertini/input_file.py index 1c99abd..685598e 100644 --- a/naglib/bertini/input_file.py +++ b/naglib/bertini/input_file.py @@ -26,10 +26,10 @@ def _ordereddict_of_type(obj, dtype): "is valid": lambda x: x in range(0, 3)}, precision={"default": 96, "is valid": lambda x: isinstance(x, int) and x >= 64}, - coeffbound={"default": 1000., # for user-defined homotopies only + coeffbound={"default": 1000., # default for user-defined homotopies only "is valid": lambda x: isinstance(x, float) and x > 0}, - degreebound={"default": 5, # for user-defined homotopies only - "is valid": lambda x: isinstance(x, int) and x > 0}, + degreebound={"default": 5., # default for user-defined homotopies only + "is valid": lambda x: isinstance(x, float) and x > 0}, ampmaxprec={"default": 1024, "is valid": lambda x: isinstance(x, int) and x >= 64}, parameterhomotopy={"default": 0, @@ -417,8 +417,8 @@ def function(self, val): @property def ndims(self): if self.variable: - nd = sum(len(v) for v in self.variable) + nd = len(sum(self.variable, [])) else: - nd = sum(len(v) for v in self.variable_group) + sum(len(v) for v in self.hom_variable_group) + nd = len(sum(self.variable_group, []) + sum(self.hom_variable_group, [])) return nd diff --git a/naglib/bertini/io.py b/naglib/bertini/io.py index bd09200..fbf561a 100644 --- a/naglib/bertini/io.py +++ b/naglib/bertini/io.py @@ -1,5 +1,5 @@ from _io import TextIOWrapper -from collections import deque, OrderedDict +from collections import deque from fractions import Fraction import os.path as op import sys @@ -14,6 +14,37 @@ from naglib.exceptions import UnclassifiedException +class BertiniResult: + def __init__(self, **kwargs): + """The output of a Bertini run. + + Parameters + ---------- + kwargs + """ + pass + + @property + def config(self): + """Configuration needed to reproduce the run.""" + return self._config + + @config.setter + def config(self, val): + assert isinstance(val, BertiniConfig) + self._config = val + + @property + def inputs(self): + """Inputs needed to reproduce the run.""" + return self._inputs + + @inputs.setter + def inputs(self, val): + assert isinstance(val, BertiniInput) + self._inputs = val + + def _line_to_complex(line: str, multi: bool = False) -> complex: real, imag = line.split(" ") return mp.mpc(real, imag) if multi else np.complex(float(real), float(imag)) @@ -44,7 +75,7 @@ def parse_input_file(fh: TextIOWrapper, stop_if: Callable = None) -> Tuple[Berti Values set in the INPUT section. """ if stop_if is None: - stop_if = lambda line: line != "" + stop_if = lambda l: l == "" config = BertiniConfig() inputs = BertiniInput() @@ -61,77 +92,72 @@ def parse_input_file(fh: TextIOWrapper, stop_if: Callable = None) -> Tuple[Berti parameter_re = re.compile(r"^parameter\s+", re.I) line = fh.readline() - while not stop_if(line): - line = line.strip(" ;") + while line and not stop_if(line): + line = line.strip(" ;\n") if line.lower() == "config": in_config = True - continue elif line.lower() == "input": in_input = True - continue elif line.lower() == "end": in_input = in_config = False - continue - elif line.startswith("%"): - continue - - if in_config: - key, val = map(lambda l: l.strip(), line.split(":")) - val = val.split("%")[0].strip(" ;") # remove comment, semicolon, trailing whitespace - - setattr(config, key.lower(), val) - - elif in_input: - if vargroup_re.match(line): - line = vargroup_re.sub("", line) - inputs.variable_group.append(re.split(r",\s*", line)) - elif var_re.match(line): - line = var_re.sub("", line) - inputs.variable.append(re.split(r",\s*", line)) - elif homvargroup_re.match(line): - line = homvargroup_re.sub("", line) - inputs.hom_variable_group.append(re.split(r",\s*", line)) - elif pathvar_re.match(line): - line = pathvar_re.sub("", line) - inputs.pathvariable.append(re.split(r",\s*", line)) - elif random_re.match(line): - line = random_re.sub("", line) - inputs.random.append(re.split(r",\s*", line)) - elif constant_re.match(line): - line = constant_re.sub("", line) - constants = re.split(r",\s*", line) - for c in constants: - inputs.constant[c] = None - elif function_re.match(line): - line = function_re.sub("", line) - functions = re.split(r",\s*", line) - for f in functions: - inputs.function[f] = None - elif parameter_re.match(line): - line = parameter_re.sub("", line) - params = re.split(r",\s*", line) - for p in params: - inputs.parameter[p] = None - else: - terms = re.split(r";\s*", line) - for term in terms: - # remove comments - term = term.split("%")[0].strip() - # split by = - term = re.split(r"\s*=\s*", term) - if len(term) != 2: - misclines.append("=".join(term)) - else: - term, val = term - if term in inputs.constant: - inputs.constant[term] = val - elif term in inputs.function: - inputs.function[term] = val - elif term in inputs.parameter: - inputs.parameter[term] = val + elif not line.startswith("%") and len(line) > 0: + if in_config: + key, val = map(lambda l: l.strip(), line.split(":")) + val = val.split("%")[0].strip(" ;") # remove comment, semicolon, trailing whitespace + + setattr(config, key.lower(), val) + + elif in_input: + if vargroup_re.match(line): + line = vargroup_re.sub("", line) + inputs.variable_group.append(re.split(r",\s*", line)) + elif var_re.match(line): + line = var_re.sub("", line) + inputs.variable.append(re.split(r",\s*", line)) + elif homvargroup_re.match(line): + line = homvargroup_re.sub("", line) + inputs.hom_variable_group.append(re.split(r",\s*", line)) + elif pathvar_re.match(line): + line = pathvar_re.sub("", line) + inputs.pathvariable.append(re.split(r",\s*", line)) + elif random_re.match(line): + line = random_re.sub("", line) + inputs.random.append(re.split(r",\s*", line)) + elif constant_re.match(line): + line = constant_re.sub("", line) + constants = re.split(r",\s*", line) + for c in constants: + inputs.constant[c] = None + elif function_re.match(line): + line = function_re.sub("", line) + functions = re.split(r",\s*", line) + for f in functions: + inputs.function[f] = None + elif parameter_re.match(line): + line = parameter_re.sub("", line) + params = re.split(r",\s*", line) + for p in params: + inputs.parameter[p] = None + else: + terms = re.split(r";\s*", line) + for term in terms: + # remove comments + term = term.split("%")[0].strip() + # split by = + term = re.split(r"\s*=\s*", term) + if len(term) != 2: + misclines.append("=".join(term)) else: - inputs.subfunction[term] = val + term, val = term + if term in inputs.constant: + inputs.constant[term] = val + elif term in inputs.function: + inputs.function[term] = val + elif term in inputs.parameter: + inputs.parameter[term] = val + else: + inputs.subfunction[term] = val line = fh.readline() @@ -163,6 +189,35 @@ def read_input_file(input_file: str) -> Tuple[BertiniConfig, BertiniInput, list] return config, inputs, misclines +def read_main_data_file(main_data_file: str) -> BertiniResult: + """ + + Parameters + ---------- + main_data_file + + Returns + ------- + result : BertiniResult + """ + if not op.isfile(main_data_file): + raise IOError(f"Main data file '{main_data_file}' not found") + + result = BertiniResult() + + with open(main_data_file, "r") as fh: + line = fh.readline() + # TODO: parse other more useful information from main_data + while line and line != "*************** input file needed to reproduce this run ***************\n": + line = fh.readline() + + c, i, _ = parse_input_file(fh, lambda l: l == "*************** version information ***************") + + result.config, result.inputs = c, i + + return result + + def read_points_file(points_file: str, tol: float = None, multi: bool = False) -> np.ndarray: """Read points from an output file. diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index ce1fdf5..eef759d 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -11,7 +11,7 @@ from typing import Union from naglib.bertini.input_file import BertiniConfig, BertiniInput -from naglib.bertini.io import (read_input_file, read_points_file, read_witness_data_file, +from naglib.bertini.io import (read_input_file, read_main_data_file, read_points_file, read_witness_data_file, write_input_file, write_points_file, extract_error_message) from naglib.exceptions import BertiniError @@ -30,13 +30,9 @@ def _which(exe: str) -> Union[str, None]: return path -class BertiniResult(object): - pass - - -class BertiniRun(object): +class BertiniRun: def __init__(self, config, inputs, **kwargs): - """Construct a BertiniRun. + """A single Bertini run. Parameters ---------- @@ -74,7 +70,8 @@ def __init__(self, config, inputs, **kwargs): if config.needs_projection_variables(): if "projection" not in kwargs: - raise ValueError("specify the variables onto which you wish to project with the keyword argument 'projection'") + raise ValueError("specify the variables onto which you wish to project with the keyword argument " + "'projection'") self._projection = kwargs["projection"] # a setting of ParameterHomotopy > 0 requires parameters @@ -219,11 +216,8 @@ def _recover_data(self): if not self._complete: return - with open(op.join(self.dirname, "main_data"), "r") as fh: - # TODO: implement read_main_data in naglib.bertini.io to return BertiniResult - self._main_data = [l.strip() for l in fh.readlines() if l != "\n"] + result = read_main_data_file(op.join(self.dirname, "main_data")) - result = BertiniResult() if self.tracktype == self.config.TZERODIM: result.finite_solutions = read_points_file(op.join(self.dirname, "finite_solutions"), multi=self.config.mptype != 0) @@ -481,7 +475,7 @@ def start(self, val): if val.shape[0] != self.config.ndims: raise ValueError(f"expected points of dimension {self.config.ndims} but you specified {val.shape[0]}") - self._start = val.as_type(np.complex) + self._start = val.astype(np.complex) @property def start_parameters(self): @@ -499,7 +493,7 @@ def start_parameters(self, val): if val.size != len(self.inputs.parameter): raise ValueError(f"expected {len(self.inputs.parameter)} parameters but you specified {val.size}") - self._start_parameters = val.as_type(np.complex) + self._start_parameters = val.astype(np.complex) @property def final_parameters(self): @@ -517,7 +511,7 @@ def final_parameters(self, val): if val.size != len(self.inputs.parameter): raise ValueError(f"expected {len(self.inputs.parameter)} parameters but you specified {val.size}") - self._final_parameters = val.as_type(np.complex) + self._final_parameters = val.astype(np.complex) @property def tracktype(self): diff --git a/test/test_io.py b/test/test_io.py index 775173b..6b402ec 100644 --- a/test/test_io.py +++ b/test/test_io.py @@ -11,42 +11,43 @@ def is_empty(x): return len(x) == 0 - -def test_read_input1(): - config, inputs, misclines = read_input_file(op.join(POS_DIM_BASE, "sampling", "input")) - - assert isinstance(config, BertiniConfig) - assert config.tracktype == 2 - assert config.mptype == 2 - assert config.precision == 96 - assert config.coeffbound == 1000 - assert config.degreebound == 5 - assert config.ampmaxprec == 1024 - assert config.parameterhomotopy == 0 - assert config.randomseed == 0 - - assert isinstance(inputs, BertiniInput) - assert is_empty(inputs.constant) - assert is_empty(inputs.variable) - assert is_empty(inputs.hom_variable_group) - assert is_empty(inputs.subfunction) - assert is_empty(inputs.parameter) - assert is_empty(inputs.random) - assert is_empty(inputs.random_real) - assert is_empty(inputs.pathvariable) - assert inputs.ndims == 3 - assert len(inputs.variable_group) == 1 - assert inputs.variable_group[0] == ["x", "y", "z"] - assert len(inputs.function) == 3 - assert inputs.function["f1"] == "(y-x^2)*(x^2+y^2+z^2-1)*(x-0.5)" - assert inputs.function["f2"] == "(z-x^3)*(x^2+y^2+z^2-1)*(y-0.5)" - assert inputs.function["f3"] == "(y-x^2)*(z-x^3)*(x^2+y^2+z^2-1)*(z-0.5)" - - assert isinstance(misclines, list) and len(misclines) == 0 +# TODO: there's a problem when running both of these tests which causes the BertiniInput in test2 +# to share its variable group with that of test1. I have no idea why. +# def test_read_input1(): +# config, inputs, misclines = read_input_file(op.join(POS_DIM_BASE, "sampling", "input")) +# +# assert isinstance(config, BertiniConfig) +# assert config.tracktype == 2 +# assert config.mptype == 2 +# assert config.precision == 96 +# assert config.coeffbound == 1000 +# assert config.degreebound == 5 +# assert config.ampmaxprec == 1024 +# assert config.parameterhomotopy == 0 +# assert config.randomseed == 0 +# +# assert isinstance(inputs, BertiniInput) +# assert is_empty(inputs.constant) +# assert is_empty(inputs.variable) +# assert is_empty(inputs.hom_variable_group) +# assert is_empty(inputs.subfunction) +# assert is_empty(inputs.parameter) +# assert is_empty(inputs.random) +# assert is_empty(inputs.random_real) +# assert is_empty(inputs.pathvariable) +# assert inputs.ndims == 3 +# assert len(inputs.variable_group) == 1 +# assert inputs.variable_group[0] == ["x", "y", "z"] +# assert len(inputs.function) == 3 +# assert inputs.function["f1"] == "(y-x^2)*(x^2+y^2+z^2-1)*(x-0.5)" +# assert inputs.function["f2"] == "(z-x^3)*(x^2+y^2+z^2-1)*(y-0.5)" +# assert inputs.function["f3"] == "(y-x^2)*(z-x^3)*(x^2+y^2+z^2-1)*(z-0.5)" +# +# assert isinstance(misclines, list) and len(misclines) == 0 def test_read_input2(): - config, inputs, misclines = read_input_file(op.join(ZERO_DIM_BASE, "parameterhomotopy", "input")) + config, inputs, misclines = read_input_file(op.join(ZERO_DIM_BASE, "parameter_homotopy", "input")) assert isinstance(config, BertiniConfig) assert config.tracktype == 0 @@ -55,7 +56,7 @@ def test_read_input2(): assert config.coeffbound == 1000 assert config.degreebound == 5 assert config.ampmaxprec == 1024 - assert config.parameterhomotopy == 0 + assert config.parameterhomotopy == 1 assert config.randomseed == 10191 assert isinstance(inputs, BertiniInput) @@ -63,16 +64,21 @@ def test_read_input2(): assert is_empty(inputs.variable) assert is_empty(inputs.hom_variable_group) assert is_empty(inputs.subfunction) - assert is_empty(inputs.parameter) + assert len(inputs.parameter) == 7 + assert inputs.parameter["a0"] is None + assert inputs.parameter["a1"] is None + assert inputs.parameter["a2"] is None + assert inputs.parameter["a3"] is None + assert inputs.parameter["a4"] is None + assert inputs.parameter["a5"] is None + assert inputs.parameter["a6"] is None assert is_empty(inputs.random) assert is_empty(inputs.random_real) assert is_empty(inputs.pathvariable) - assert inputs.ndims == 3 + assert inputs.ndims == 1 assert len(inputs.variable_group) == 1 - assert inputs.variable_group[0] == ["x", "y", "z"] - assert len(inputs.function) == 3 - assert inputs.function["f1"] == "(y-x^2)*(x^2+y^2+z^2-1)*(x-0.5)" - assert inputs.function["f2"] == "(z-x^3)*(x^2+y^2+z^2-1)*(y-0.5)" - assert inputs.function["f3"] == "(y-x^2)*(z-x^3)*(x^2+y^2+z^2-1)*(z-0.5)" + assert inputs.variable_group[0] == ["x"] + assert len(inputs.function) == 1 + assert inputs.function["f"] == "a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))" assert isinstance(misclines, list) and len(misclines) == 0 diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index c6d95cc..23e32cd 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -4,12 +4,12 @@ import numpy as np -from naglib.bertini.io import read_points_file +from naglib.bertini.io import write_input_file from naglib.bertini.run import BertiniRun from naglib.bertini.input_file import BertiniInput, BertiniConfig -class TestParameterHomotopy(): +class TestParameterHomotopy: def setup_method(self): self.working_dir = op.join(ZERO_DIM_BASE, "parameter_homotopy") self.inputs = BertiniInput(variable_group=[["x"]], @@ -18,25 +18,28 @@ def setup_method(self): self.config = BertiniConfig(parameterhomotopy=1, randomseed=10191) + print("initial run") brun = BertiniRun(self.config, self.inputs) self.ab_initio_result = brun.run(dirname=self.working_dir) - def test_ab_initio(self): + def test_ab_initio_result(self): finite_solutions = np.array([[0.78101599+0.18185757j, 0.33253178+1.4856318j, -0.71413828+1.01669647j, -0.53917013-0.04838107j, -0.65402653-0.7627159j , 0.43428293-0.98042348j]]) assert np.linalg.norm(finite_solutions - self.ab_initio_result.finite_solutions) < 1e-8 - # def test_parameter_homotopy2(self): + def test_parameter_homotopy2(self): + start_parameters = self.ab_initio_result.start_parameters + final_parameters = np.array([1.1, 2.4, 0.8, 3.6, -0.52, -1.8, 4.4], dtype=np.complex) + self.config.parameterhomotopy = 2 + brun = BertiniRun(self.config, self.inputs, start=self.ab_initio_result.nonsingular_solutions, + start_parameters=start_parameters, final_parameters=final_parameters) + self.final_result = brun.run(dirname=self.working_dir) + assert isinstance(self.final_result.config, BertiniConfig) + assert isinstance(self.final_result.inputs, BertiniInput) -def test_parameter_homotopy2(): - inputs = BertiniInput(variable_group=[["x"]], - parameter=OrderedDict((f"a{i}", None) for i in range(7)), - function=OrderedDict(f="a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6)))))")) - - start_parameters = read_points_file(op.join(ZERO_DIM_BASE, "parameter_homotopy", "start_parameters")) - start_points = read_points_file(op.join(ZERO_DIM_BASE, "parameter_homotopy", "start")) - config = BertiniConfig(parameterhomotopy=2, randomseed=10191) - brun = BertiniRun(config, inputs) + def teardown_method(self): + self.config.parameterhomotopy = 1 + write_input_file(self.config, self.inputs, op.join(self.working_dir, "input")) \ No newline at end of file From 6ecb2ed1c07ef5cdd6f47ffd22742b3d832646fe Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Thu, 27 Jun 2019 06:56:29 -0400 Subject: [PATCH 12/25] add setup instructions, remove some dead code --- .gitignore | 1 + README.md | 10 ++++- naglib/bertini/run.py | 94 ------------------------------------------- setup.py | 2 +- 4 files changed, 11 insertions(+), 96 deletions(-) diff --git a/.gitignore b/.gitignore index 0a293cd..7f045c0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .spyproject/ __pycache__ +*.egg-info/ # test output test/data/zero_dim/**/failed_paths diff --git a/README.md b/README.md index 413a4c5..5a4fc74 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,12 @@ Mostly, it's just a wrapper around [Bertini](https://bertini.nd.edu) (sold separ Don't install NAGlib. It's not ready yet. -If you want something right now and you're into Julia, you might try [Bertini.jl](https://github.com/PBrdng/Bertini.jl). \ No newline at end of file +If you want something right now and you're into Julia, you might try [Bertini.jl](https://github.com/PBrdng/Bertini.jl). + +If you absolutely must, ensure you have Python 3, NumPy, and [mpmath](https://mpmath.readthedocs.io/en/latest/), then run + +```shell +$ python setup.py develop +``` + +in this directory. \ No newline at end of file diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index eef759d..b01a518 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -112,100 +112,6 @@ def __init__(self, config, inputs, **kwargs): self._complete = False - def _recover_components(self, witness_data): - """ - """ - from sympy import sympify - from naglib.core.algebra import LinearSlice - from naglib.core.base import AffinePoint, ProjectivePoint - from naglib.core.geometry import IrreducibleComponent - from naglib.core.witnessdata import WitnessPoint, WitnessSet - system = self._system - variables = system.variables -# if system.homvar: -# proj_dim = len(variables) - #homsys = system -# else: -# proj_dim = len(system.variables) + 1 - #homsys = system.homogenize() - homvar = sympify('_homvar') - while homvar in system.variables: - homvar = sympify('_' + str(homvar)) - homsys = system.homogenize(homvar) - homvars = homsys.variables - - components = [] - - for c in witness_data: - codim = c['codim'] - homVarConst = c['homVarConst'] - points = c['points'] - coeffs = c['slice'] - rand_mat = c['A'] - homog_mat = c['W'] - homog_vec = c['H'] - hvc = c['homVarConst'] - patch_coeff = c['p'] - - comp_isprojective = homVarConst == 0 - - hslice = None - if coeffs: - if comp_isprojective: - hslice = LinearSlice(coeffs, homvars, homvar) - if not system.homvar: - lslice = hslice.dehomogenize() - else: - lslice = LinearSlice(coeffs, variables) - else: - lslice = None - - dim_list = {} - - hcoord = None - for point in points: - comp_id = point['component number'] - if comp_isprojective: - hcoord = point['coordinates'] - if not system.homvar: - coord = ProjectivePoint(hcoord).dehomogenize() - else: - coord = AffinePoint(point['coordinates']) - - wpoint = WitnessPoint(coord, comp_id, - corank=point['corank'], - condition_number=point['condition number'], - smallest_nonzero=point['smallest nonzero'], - largest_zero=point['largest zero'], - point_type=point['type'], - multiplicity=point['multiplicity'], - deflations=point['deflations'], - precision=point['precision'], - last_approximation=point['last approximation'], - homogeneous_coordinates=hcoord) - - if comp_id not in dim_list: - dim_list[comp_id] = [] - - dim_list[comp_id].append(wpoint) - - for comp_id in dim_list.keys(): - ws = WitnessSet(system.copy(), - lslice, - dim_list[comp_id], - witness_data, - homogeneous_slice=hslice) - component = IrreducibleComponent(ws, codim, comp_id, - randomization_matrix=rand_mat, - homogenization_matrix=homog_mat, - homogenization_vector=homog_vec, - homogenization_variable=hvc, - patch_coefficients=patch_coeff) - - components.append(component) - - return components - def _recover_data(self): """Recover data from a run. diff --git a/setup.py b/setup.py index ba7154b..50a2f8a 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='naglib', version='0.1.0', - packages=['naglib', 'naglib.core', 'naglib.bertini'], + packages=['naglib', 'naglib.bertini'], url='https://github.com/aliddell/naglib', license='BSD', author='Alan', From 75a2f2665b505aa97c2a31ce66f697865c02b9ba Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Thu, 27 Jun 2019 13:03:26 -0400 Subject: [PATCH 13/25] allow mpi_path=None to be specified at BertiniRun.__init__ --- naglib/bertini/run.py | 2 +- requirements.txt | 6 +----- test/test_parameter_homotopy.py | 4 ++-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index b01a518..2d81da6 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -104,7 +104,7 @@ def __init__(self, config, inputs, **kwargs): self._bertini = bertini if "mpi_path" in kwargs: - if not op.isfile(kwargs["mpi_path"]): + if kwargs["mpi_path"] is not None and not op.isfile(kwargs["mpi_path"]): raise OSError(f"didn't find MPI executable at '{kwargs['mpi_path']}'") self._mpi = kwargs["mpi_path"] else: diff --git a/requirements.txt b/requirements.txt index 90c0d66..a5dabd9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,3 @@ -certifi==2019.3.9 -fastcache==1.1.0 -mkl-fft==1.0.12 -mkl-random==1.0.2 mpmath==1.1.0 numpy==1.16.4 -wincertstore==0.2 +pytest==4.6.3 \ No newline at end of file diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index 23e32cd..58b9839 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -19,7 +19,7 @@ def setup_method(self): self.config = BertiniConfig(parameterhomotopy=1, randomseed=10191) print("initial run") - brun = BertiniRun(self.config, self.inputs) + brun = BertiniRun(self.config, self.inputs, mpi_path=None) self.ab_initio_result = brun.run(dirname=self.working_dir) def test_ab_initio_result(self): @@ -34,7 +34,7 @@ def test_parameter_homotopy2(self): self.config.parameterhomotopy = 2 brun = BertiniRun(self.config, self.inputs, start=self.ab_initio_result.nonsingular_solutions, - start_parameters=start_parameters, final_parameters=final_parameters) + start_parameters=start_parameters, final_parameters=final_parameters, mpi_path=None) self.final_result = brun.run(dirname=self.working_dir) assert isinstance(self.final_result.config, BertiniConfig) From 37f987ca0a275005b4521b4d12664db8b5d1ed38 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Sat, 29 Jun 2019 13:50:47 -0400 Subject: [PATCH 14/25] fixes shallow copy bug --- .gitignore | 2 +- README.md | 1 + naglib/bertini/input_file.py | 5 +- naglib/bertini/io.py | 15 +- .../AppendixQuickStart/._.DS_Store | Bin 0 -> 82 bytes .../AppendixQuickStart/FirstRun.input | 6 + .../AppendixQuickStart/Homogeneous.input | 6 + .../AppendixQuickStart/MoreAccuracy.input | 10 + .../ParameterHomotopy.input | 11 ++ .../AppendixQuickStart/Sqrt1.input | 6 + .../AppendixQuickStart/Subfunctions.input | 12 ++ .../AppendixQuickStart/TwistedCubic.input | 11 ++ .../AppendixQuickStart/TwoGroups.input | 8 + .../AppendixQuickStart/UserHomotopy.start | 5 + .../UserHomotopy_Affine.input | 17 ++ .../UserHomotopy_Projective.input | 17 ++ .../AppendixQuickStart/final_parameters | 3 + .../Chap11AdvancedPosDim/._.DS_Store | Bin 0 -> 82 bytes .../Chap11AdvancedPosDim/Deflation.input | 11 ++ .../Chap11AdvancedPosDim/LineCircle.input | 10 + .../Chap11AdvancedPosDim/LineCircle.print | 11 ++ .../Chap11AdvancedPosDim/MaxCodimension.input | 13 ++ .../SpecificCodimension.input | 15 ++ .../Chap12Intersection/._.DS_Store | Bin 0 -> 82 bytes .../DiagonalIntersection.input | 17 ++ .../DiagonalIntersection.start | 6 + .../IntersectComponents.input | 19 ++ .../Chap14RealSets/._.DS_Store | Bin 0 -> 82 bytes .../Chap14RealSets/FritzJohnHomotopy.input | 24 +++ .../Chap14RealSets/FritzJohnInitial.input | 17 ++ .../Chap16ProjectionsOfSets/._.DS_Store | Bin 0 -> 82 bytes .../Discriminant.input | 23 +++ .../Chap16ProjectionsOfSets/Enneper.input | 12 ++ .../Chap1PolynomialSystems/._.DS_Store | Bin 0 -> 82 bytes .../._CircleAndYaxisC0.input | Bin 0 -> 1420 bytes .../CircleAndYaxisC0.input | 10 + .../CircleAndYaxisC1.input | 10 + .../Chap1PolynomialSystems/degree10.input | 9 + .../Chap1PolynomialSystems/degree10eval.input | 11 ++ .../degree10eval.points | 22 +++ .../Chap1PolynomialSystems/input | 7 + .../Chap1PolynomialSystems/subfunctions.input | 9 + .../AroundTheUnitCircle.input | 16 ++ .../AroundTheUnitCircle.start | 4 + .../AroundTheUnitCircleAlt.input | 14 ++ .../Chap4ProjectiveSpace/._.DS_Store | Bin 0 -> 82 bytes .../Chap4ProjectiveSpace/Eigenvalue2x2.input | 11 ++ .../GeneralizedEigenvalue.input | 11 ++ .../Chap4ProjectiveSpace/TwoCircles.input | 13 ++ .../Chap5HomotopyTypes/._.DS_Store | Bin 0 -> 82 bytes .../Chap5HomotopyTypes/LagrangePoints.input | 33 ++++ .../LagrangePoints_regen.input | 37 ++++ .../Chap5HomotopyTypes/SixR_2hom.input | 67 +++++++ .../Chap5HomotopyTypes/SixR_4hom.input | 69 +++++++ .../TwoHyperbolas_1Hom.input | 7 + .../TwoHyperbolas_2Hom.input | 8 + .../Chap5HomotopyTypes/TwoQuadrics_1hom.input | 7 + .../Chap5HomotopyTypes/TwoQuadrics_2hom.input | 8 + .../TwoSpheres_OneCone.input | 13 ++ .../ninepoint_regen1group.input | 149 +++++++++++++++ .../ninepoint_regen2groups.input | 150 +++++++++++++++ .../ninepoint_regen4groups.input | 152 +++++++++++++++ .../Chap6ParameterHomotopy/._.DS_Store | Bin 0 -> 82 bytes .../LagrangePoints.input | 33 ++++ .../LagrangePoints_parameter.input | 35 ++++ .../SixR_parameter.input | 72 ++++++++ .../Chap6ParameterHomotopy/StewartGough.input | 125 +++++++++++++ .../ninepoint_parameter.input | 161 ++++++++++++++++ .../Chap6ParameterHomotopy/sextic.input | 10 + .../Chap7AdvancedIsolated/._.DS_Store | Bin 0 -> 82 bytes .../CircleParabola_eval.input | 14 ++ .../CircleParabola_newton.input | 15 ++ .../Chap7AdvancedIsolated/CondNumCalc.input | 17 ++ .../Chap7AdvancedIsolated/CondNumCalc.start | 14 ++ .../Chap7AdvancedIsolated/FixedPoint.input | 15 ++ .../Chap7AdvancedIsolated/FunctionEval.input | 17 ++ .../Chap7AdvancedIsolated/FunctionEval.start | 4 + .../Chap7AdvancedIsolated/HighCondNum.input | 7 + .../HighCondNum_sharpen.input | 12 ++ .../HyperbolaParabola.input | 7 + .../HyperbolaParabola_sharpen.input | 12 ++ .../NewtonHomotopy.input | 15 ++ .../Chap7AdvancedIsolated/RoundingError.input | 12 ++ .../Chap7AdvancedIsolated/ScaledSystem.input | 11 ++ .../Chap7AdvancedIsolated/SharpenDigits.input | 12 ++ .../Chap7AdvancedIsolated/Unscale.input | 14 ++ .../UserDefined_NewtonHomotopy.input | 14 ++ .../UserDefined_ProductSpace.input | 19 ++ .../UserDefined_ProductSpace.start | 8 + .../Chap8PositiveDimensional/._.DS_Store | Bin 0 -> 82 bytes .../BricardSixR.input | 80 ++++++++ .../GriffisDuffy.input | 152 +++++++++++++++ .../GriffisDuffyFoldable.input | 167 +++++++++++++++++ .../GriffisDuffyI.input | 173 ++++++++++++++++++ .../GriffisDuffyII.input | 165 +++++++++++++++++ .../GriffisDuffyILegs.input | 170 +++++++++++++++++ .../Illustrative.input | 14 ++ .../SmallConstant.input | 22 +++ .../Chap8PositiveDimensional/ThreeLines.input | 11 ++ .../Chap9WitnessGeneration/._.DS_Store | Bin 0 -> 82 bytes .../AdjacentMinors_DimByDim.input | 20 ++ .../AdjacentMinors_classical.input | 20 ++ .../AdjacentMinors_regenCascade.input | 20 ++ test/data/Bertini_examples/README.md | 4 + test/data/README.md | 4 + test/test_io.py | 71 ++++--- 106 files changed, 2885 insertions(+), 43 deletions(-) create mode 100644 test/data/Bertini_examples/AppendixQuickStart/._.DS_Store create mode 100644 test/data/Bertini_examples/AppendixQuickStart/FirstRun.input create mode 100644 test/data/Bertini_examples/AppendixQuickStart/Homogeneous.input create mode 100644 test/data/Bertini_examples/AppendixQuickStart/MoreAccuracy.input create mode 100644 test/data/Bertini_examples/AppendixQuickStart/ParameterHomotopy.input create mode 100644 test/data/Bertini_examples/AppendixQuickStart/Sqrt1.input create mode 100644 test/data/Bertini_examples/AppendixQuickStart/Subfunctions.input create mode 100644 test/data/Bertini_examples/AppendixQuickStart/TwistedCubic.input create mode 100644 test/data/Bertini_examples/AppendixQuickStart/TwoGroups.input create mode 100644 test/data/Bertini_examples/AppendixQuickStart/UserHomotopy.start create mode 100644 test/data/Bertini_examples/AppendixQuickStart/UserHomotopy_Affine.input create mode 100644 test/data/Bertini_examples/AppendixQuickStart/UserHomotopy_Projective.input create mode 100644 test/data/Bertini_examples/AppendixQuickStart/final_parameters create mode 100644 test/data/Bertini_examples/Chap11AdvancedPosDim/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap11AdvancedPosDim/Deflation.input create mode 100644 test/data/Bertini_examples/Chap11AdvancedPosDim/LineCircle.input create mode 100644 test/data/Bertini_examples/Chap11AdvancedPosDim/LineCircle.print create mode 100644 test/data/Bertini_examples/Chap11AdvancedPosDim/MaxCodimension.input create mode 100644 test/data/Bertini_examples/Chap11AdvancedPosDim/SpecificCodimension.input create mode 100644 test/data/Bertini_examples/Chap12Intersection/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap12Intersection/DiagonalIntersection.input create mode 100644 test/data/Bertini_examples/Chap12Intersection/DiagonalIntersection.start create mode 100644 test/data/Bertini_examples/Chap12Intersection/IntersectComponents.input create mode 100644 test/data/Bertini_examples/Chap14RealSets/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap14RealSets/FritzJohnHomotopy.input create mode 100644 test/data/Bertini_examples/Chap14RealSets/FritzJohnInitial.input create mode 100644 test/data/Bertini_examples/Chap16ProjectionsOfSets/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap16ProjectionsOfSets/Discriminant.input create mode 100644 test/data/Bertini_examples/Chap16ProjectionsOfSets/Enneper.input create mode 100644 test/data/Bertini_examples/Chap1PolynomialSystems/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap1PolynomialSystems/._CircleAndYaxisC0.input create mode 100644 test/data/Bertini_examples/Chap1PolynomialSystems/CircleAndYaxisC0.input create mode 100644 test/data/Bertini_examples/Chap1PolynomialSystems/CircleAndYaxisC1.input create mode 100644 test/data/Bertini_examples/Chap1PolynomialSystems/degree10.input create mode 100644 test/data/Bertini_examples/Chap1PolynomialSystems/degree10eval.input create mode 100644 test/data/Bertini_examples/Chap1PolynomialSystems/degree10eval.points create mode 100644 test/data/Bertini_examples/Chap1PolynomialSystems/input create mode 100644 test/data/Bertini_examples/Chap1PolynomialSystems/subfunctions.input create mode 100644 test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircle.input create mode 100644 test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircle.start create mode 100644 test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircleAlt.input create mode 100644 test/data/Bertini_examples/Chap4ProjectiveSpace/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap4ProjectiveSpace/Eigenvalue2x2.input create mode 100644 test/data/Bertini_examples/Chap4ProjectiveSpace/GeneralizedEigenvalue.input create mode 100644 test/data/Bertini_examples/Chap4ProjectiveSpace/TwoCircles.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/LagrangePoints.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/LagrangePoints_regen.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/SixR_2hom.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/SixR_4hom.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/TwoHyperbolas_1Hom.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/TwoHyperbolas_2Hom.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/TwoQuadrics_1hom.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/TwoQuadrics_2hom.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/TwoSpheres_OneCone.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen1group.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen2groups.input create mode 100644 test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen4groups.input create mode 100644 test/data/Bertini_examples/Chap6ParameterHomotopy/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap6ParameterHomotopy/LagrangePoints.input create mode 100644 test/data/Bertini_examples/Chap6ParameterHomotopy/LagrangePoints_parameter.input create mode 100644 test/data/Bertini_examples/Chap6ParameterHomotopy/SixR_parameter.input create mode 100644 test/data/Bertini_examples/Chap6ParameterHomotopy/StewartGough.input create mode 100644 test/data/Bertini_examples/Chap6ParameterHomotopy/ninepoint_parameter.input create mode 100644 test/data/Bertini_examples/Chap6ParameterHomotopy/sextic.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/CircleParabola_eval.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/CircleParabola_newton.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/CondNumCalc.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/CondNumCalc.start create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/FixedPoint.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/FunctionEval.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/FunctionEval.start create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/HighCondNum.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/HighCondNum_sharpen.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/HyperbolaParabola.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/HyperbolaParabola_sharpen.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/NewtonHomotopy.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/RoundingError.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/ScaledSystem.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/SharpenDigits.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/Unscale.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_NewtonHomotopy.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_ProductSpace.input create mode 100644 test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_ProductSpace.start create mode 100644 test/data/Bertini_examples/Chap8PositiveDimensional/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap8PositiveDimensional/BricardSixR.input create mode 100644 test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffy.input create mode 100644 test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyFoldable.input create mode 100644 test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyI.input create mode 100644 test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyII.input create mode 100644 test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyILegs.input create mode 100644 test/data/Bertini_examples/Chap8PositiveDimensional/Illustrative.input create mode 100644 test/data/Bertini_examples/Chap8PositiveDimensional/SmallConstant.input create mode 100644 test/data/Bertini_examples/Chap8PositiveDimensional/ThreeLines.input create mode 100644 test/data/Bertini_examples/Chap9WitnessGeneration/._.DS_Store create mode 100644 test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_DimByDim.input create mode 100644 test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_classical.input create mode 100644 test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_regenCascade.input create mode 100644 test/data/Bertini_examples/README.md create mode 100644 test/data/README.md diff --git a/.gitignore b/.gitignore index 7f045c0..a4b870d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ .idea/ .spyproject/ - __pycache__ *.egg-info/ +.DS_Store # test output test/data/zero_dim/**/failed_paths diff --git a/README.md b/README.md index 5a4fc74..e173565 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ NAGlib is a Python library for numerical algebraic geometry. Mostly, it's just a wrapper around [Bertini](https://bertini.nd.edu) (sold separately). +(Note: I am not a member of Bertini team, just an interested user who likes automating things.) ## Installing NAGlib diff --git a/naglib/bertini/input_file.py b/naglib/bertini/input_file.py index 685598e..9e31579 100644 --- a/naglib/bertini/input_file.py +++ b/naglib/bertini/input_file.py @@ -1,3 +1,4 @@ +from copy import deepcopy from collections import OrderedDict from numbers import Number @@ -95,7 +96,7 @@ def __init__(self, **kwargs): arg_val = kwargs.pop(arg_name) self.__setattr__(arg_name, arg_val) else: - self.__setattr__(arg_name, PARAMETERS[arg_name]["default"]) + self.__setattr__(arg_name, deepcopy(PARAMETERS[arg_name]["default"])) if kwargs: key, _ = kwargs.popitem() @@ -231,7 +232,7 @@ def __init__(self, **kwargs): arg_val = kwargs.pop(arg_name) self.__setattr__(arg_name, arg_val) else: - self.__setattr__(arg_name, INPUT_TYPES[arg_name]["default"]) + self.__setattr__(arg_name, deepcopy(INPUT_TYPES[arg_name]["default"])) if kwargs: key, _ = kwargs.popitem() diff --git a/naglib/bertini/io.py b/naglib/bertini/io.py index fbf561a..68d8e72 100644 --- a/naglib/bertini/io.py +++ b/naglib/bertini/io.py @@ -93,15 +93,26 @@ def parse_input_file(fh: TextIOWrapper, stop_if: Callable = None) -> Tuple[Berti line = fh.readline() while line and not stop_if(line): - line = line.strip(" ;\n") + line = line.strip() if line.lower() == "config": in_config = True elif line.lower() == "input": in_input = True - elif line.lower() == "end": + elif line.lower().strip(";") == "end": in_input = in_config = False elif not line.startswith("%") and len(line) > 0: + if not line.endswith(";"): # statement spans several lines + multiline = line + line = fh.readline() + while line and not line.endswith(";"): + multiline += " " + line.strip() + line = fh.readline() + + line = multiline + + line = line.strip(" ;") + if in_config: key, val = map(lambda l: l.strip(), line.split(":")) val = val.split("%")[0].strip(" ;") # remove comment, semicolon, trailing whitespace diff --git a/test/data/Bertini_examples/AppendixQuickStart/._.DS_Store b/test/data/Bertini_examples/AppendixQuickStart/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/AppendixQuickStart/FirstRun.input b/test/data/Bertini_examples/AppendixQuickStart/FirstRun.input new file mode 100644 index 0000000..525ab1d --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/FirstRun.input @@ -0,0 +1,6 @@ + variable_group x,y; + function f,g; + + f = x^2 - 1; + g = y^2 - 1; +END; diff --git a/test/data/Bertini_examples/AppendixQuickStart/Homogeneous.input b/test/data/Bertini_examples/AppendixQuickStart/Homogeneous.input new file mode 100644 index 0000000..91951cf --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/Homogeneous.input @@ -0,0 +1,6 @@ +% Homogeneous.input + function f; + hom_variable_group x,y; + + f = x^2 - y^2; +END; diff --git a/test/data/Bertini_examples/AppendixQuickStart/MoreAccuracy.input b/test/data/Bertini_examples/AppendixQuickStart/MoreAccuracy.input new file mode 100644 index 0000000..58bf627 --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/MoreAccuracy.input @@ -0,0 +1,10 @@ +% MoreAccuracy.input +CONFIG + FinalTol:1e-20; +END; +INPUT + function f; + variable_group x; + + f = x^2 - 1; +END; diff --git a/test/data/Bertini_examples/AppendixQuickStart/ParameterHomotopy.input b/test/data/Bertini_examples/AppendixQuickStart/ParameterHomotopy.input new file mode 100644 index 0000000..26bca68 --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/ParameterHomotopy.input @@ -0,0 +1,11 @@ +% ParameterHomotopy.input +CONFIG + ParameterHomotopy:1; +END; +INPUT + variable_group x; + function f; + parameter s; + + f = x^2-s; +END; diff --git a/test/data/Bertini_examples/AppendixQuickStart/Sqrt1.input b/test/data/Bertini_examples/AppendixQuickStart/Sqrt1.input new file mode 100644 index 0000000..d893dd0 --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/Sqrt1.input @@ -0,0 +1,6 @@ +% Sqrt1.input + function f; + variable_group x; + + f = x^2 - 1; +END; diff --git a/test/data/Bertini_examples/AppendixQuickStart/Subfunctions.input b/test/data/Bertini_examples/AppendixQuickStart/Subfunctions.input new file mode 100644 index 0000000..6347c1f --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/Subfunctions.input @@ -0,0 +1,12 @@ +% Subfunctions.input + variable_group x,y,z; + function f1,f2,f3; + + S = x^2+y^2+z^2-1; + T = y-x^2; + U = x*y-z; + + f1 = S*T*(x-2); + f2 = S*U*(y-2); + f3 = S*T*U*(z-2); +END; diff --git a/test/data/Bertini_examples/AppendixQuickStart/TwistedCubic.input b/test/data/Bertini_examples/AppendixQuickStart/TwistedCubic.input new file mode 100644 index 0000000..acdc915 --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/TwistedCubic.input @@ -0,0 +1,11 @@ +% TwistedCubic.input +CONFIG + TrackType:1; +END; +INPUT + variable_group x,y,z; + function f1,f2; + + f1 = x^2-y; + f2 = x^3-z; +END; diff --git a/test/data/Bertini_examples/AppendixQuickStart/TwoGroups.input b/test/data/Bertini_examples/AppendixQuickStart/TwoGroups.input new file mode 100644 index 0000000..7f734e4 --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/TwoGroups.input @@ -0,0 +1,8 @@ +% TwoGroups.input + variable_group z1; + variable_group z2; + function f1,f2; + + f1 = (29/16)*z1^3 - 2*z1*z2; + f2 = z2 - z1^2; +END; diff --git a/test/data/Bertini_examples/AppendixQuickStart/UserHomotopy.start b/test/data/Bertini_examples/AppendixQuickStart/UserHomotopy.start new file mode 100644 index 0000000..f89f545 --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/UserHomotopy.start @@ -0,0 +1,5 @@ +2 + +-1.0 0.0 + +1.0 0.0 diff --git a/test/data/Bertini_examples/AppendixQuickStart/UserHomotopy_Affine.input b/test/data/Bertini_examples/AppendixQuickStart/UserHomotopy_Affine.input new file mode 100644 index 0000000..58f5f7a --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/UserHomotopy_Affine.input @@ -0,0 +1,17 @@ +% UserHomotopy_Affine.input +CONFIG + UserHomotopy:1; +END; +INPUT + variable x; + function f; + pathvariable t; + parameter s; + constant gamma; + + gamma = 0.8 - 1.2*I; + s = t; + + f = (x^2-1)*gamma*s + (x^2)*(1-s); + % Note: t does not explicitly appear in f +END; diff --git a/test/data/Bertini_examples/AppendixQuickStart/UserHomotopy_Projective.input b/test/data/Bertini_examples/AppendixQuickStart/UserHomotopy_Projective.input new file mode 100644 index 0000000..1fa7cae --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/UserHomotopy_Projective.input @@ -0,0 +1,17 @@ +% UserHomotopy_Projective.input +CONFIG + UserHomotopy:2; +END; +INPUT + variable_group x; + function f; + pathvariable t; + parameter s; + constant gamma; + + gamma = 0.8 - 1.2*I; + s = t; + + f = (x^2-1)*gamma*s + (x^2)*(1-s); + % Note: t does not explicitly appear in f +END; diff --git a/test/data/Bertini_examples/AppendixQuickStart/final_parameters b/test/data/Bertini_examples/AppendixQuickStart/final_parameters new file mode 100644 index 0000000..22825f5 --- /dev/null +++ b/test/data/Bertini_examples/AppendixQuickStart/final_parameters @@ -0,0 +1,3 @@ +1 + +2 0 diff --git a/test/data/Bertini_examples/Chap11AdvancedPosDim/._.DS_Store b/test/data/Bertini_examples/Chap11AdvancedPosDim/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap11AdvancedPosDim/Deflation.input b/test/data/Bertini_examples/Chap11AdvancedPosDim/Deflation.input new file mode 100644 index 0000000..9cb106f --- /dev/null +++ b/test/data/Bertini_examples/Chap11AdvancedPosDim/Deflation.input @@ -0,0 +1,11 @@ +% Deflation.input +CONFIG + TrackType:1; +END; +INPUT + variable_group x,y; + function cylinder,sphere; + + cylinder = x^2 + y^2 - 1; + sphere = x^2 + y^2 + z^2 - 1; +END; diff --git a/test/data/Bertini_examples/Chap11AdvancedPosDim/LineCircle.input b/test/data/Bertini_examples/Chap11AdvancedPosDim/LineCircle.input new file mode 100644 index 0000000..25d34db --- /dev/null +++ b/test/data/Bertini_examples/Chap11AdvancedPosDim/LineCircle.input @@ -0,0 +1,10 @@ +% LineCircle.input +CONFIG + TrackType:1; +END; +INPUT + function f; + variable_group x,y; + + f = (x - y)*(x^2 + y^2 - 1); +END; diff --git a/test/data/Bertini_examples/Chap11AdvancedPosDim/LineCircle.print b/test/data/Bertini_examples/Chap11AdvancedPosDim/LineCircle.print new file mode 100644 index 0000000..80822ae --- /dev/null +++ b/test/data/Bertini_examples/Chap11AdvancedPosDim/LineCircle.print @@ -0,0 +1,11 @@ +% LineCircle.print +CONFIG + TrackType:4; % print witness set + MPType:0; % print using double precision +END; +INPUT + function f; + variable_group x,y; + + f = (x - y)*(x^2 + y^2 - 1); +END; diff --git a/test/data/Bertini_examples/Chap11AdvancedPosDim/MaxCodimension.input b/test/data/Bertini_examples/Chap11AdvancedPosDim/MaxCodimension.input new file mode 100644 index 0000000..9ba9059 --- /dev/null +++ b/test/data/Bertini_examples/Chap11AdvancedPosDim/MaxCodimension.input @@ -0,0 +1,13 @@ +% MaxCodimension.input +CONFIG + TrackType:1; % compute a numerical irred. decomp. + MaxCodimension:2; % for components of codim <= 2 +END; +INPUT + variable_group x,y,z; + function f1,f2,f3; + + f1 = x*(x^2-y-z^2); + f2 = x*(x+y+z^2-2)*(y-5); + f3 = x*(x^2+x-2)*(z-2); +END; diff --git a/test/data/Bertini_examples/Chap11AdvancedPosDim/SpecificCodimension.input b/test/data/Bertini_examples/Chap11AdvancedPosDim/SpecificCodimension.input new file mode 100644 index 0000000..c3f1f28 --- /dev/null +++ b/test/data/Bertini_examples/Chap11AdvancedPosDim/SpecificCodimension.input @@ -0,0 +1,15 @@ +% SpecificCodimension.input +% for components of codim = 2 +CONFIG + TrackType:1; % compute a numerical irred. decomp. + SpecificCodimension:2; % for components of codim = 2 + WitnessGenType:1; % using dimension-by-dimension +END; +INPUT + variable_group x,y,z; + function f1,f2,f3; + + f1 = x*(x^2-y-z^2); + f2 = x*(x+y+z^2-2)*(y-5); + f3 = x*(x^2+x-2)*(z-2); +END; diff --git a/test/data/Bertini_examples/Chap12Intersection/._.DS_Store b/test/data/Bertini_examples/Chap12Intersection/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap12Intersection/DiagonalIntersection.input b/test/data/Bertini_examples/Chap12Intersection/DiagonalIntersection.input new file mode 100644 index 0000000..c3b31b3 --- /dev/null +++ b/test/data/Bertini_examples/Chap12Intersection/DiagonalIntersection.input @@ -0,0 +1,17 @@ +% DiagonalIntersection.input +CONFIG + UserHomotopy:2; +END; +INPUT + function FA,FB,L1,L2; + variable_group x1,x2,y1,y2; + pathvariable T; + parameter t; + random gamma; + + t = T; + FA = x1; + FB = y1*y2; + L1 = gamma*t*(2*x1 + x2 - 2) + (1-t)*(x1 - y1); + L2 = gamma*t*(x1 + 3*y2 + 4) + (1-t)*(x2 - y2); +END; diff --git a/test/data/Bertini_examples/Chap12Intersection/DiagonalIntersection.start b/test/data/Bertini_examples/Chap12Intersection/DiagonalIntersection.start new file mode 100644 index 0000000..be88eae --- /dev/null +++ b/test/data/Bertini_examples/Chap12Intersection/DiagonalIntersection.start @@ -0,0 +1,6 @@ +1 + +0 0 +2 0 +-4 0 +0 0 diff --git a/test/data/Bertini_examples/Chap12Intersection/IntersectComponents.input b/test/data/Bertini_examples/Chap12Intersection/IntersectComponents.input new file mode 100644 index 0000000..bc11465 --- /dev/null +++ b/test/data/Bertini_examples/Chap12Intersection/IntersectComponents.input @@ -0,0 +1,19 @@ +% IntersectComponents.input +CONFIG + UserHomotopy:2; +END; +INPUT + function FA,FB,L1,L2,L3,L4; + variable_group x1,x2,x3,y1,y2,y3; + pathvariable T; + parameter t; + random gamma; + + t = T; + FA = (x1*x2 - x3)*(x1^2 - x2); + FB = (y1*y2 - y3)*(y1^2 - y2); + L1 = gamma*t*(x1+2*x3-2) + (1-t)*(x1-y1); + L2 = gamma*t*(x2+x3-1) + (1-t)*(x2-y2); + L3 = gamma*t*(y1+2*y3-2) + (1-t)*(x3-y3); + L4 = gamma*t*(y2+y3-1) + (1-t)*(x1-2*x2+5*x3-3*y1-4*y2+y3-3); +END; diff --git a/test/data/Bertini_examples/Chap14RealSets/._.DS_Store b/test/data/Bertini_examples/Chap14RealSets/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap14RealSets/FritzJohnHomotopy.input b/test/data/Bertini_examples/Chap14RealSets/FritzJohnHomotopy.input new file mode 100644 index 0000000..cb275c4 --- /dev/null +++ b/test/data/Bertini_examples/Chap14RealSets/FritzJohnHomotopy.input @@ -0,0 +1,24 @@ +% FritzJohnHomotopy.input +CONFIG + UserHomotopy:2; +END; +INPUT + function F,G1,G2,patch; + variable_group x1,x2; + variable_group l0,l1; + constant y1,y2,eps,a0,a1; + pathvariable T; + parameter t; + + t = T; + y1 = 0.5; + y2 = 0.8; + eps = 1.1 + 0.7*I; + a0 = -1.3; + a1 = 1.7; + + F = x2^2 + x1^2*(x1-1)^3*(x1-2) - t*eps; + G1 = l0*(x1-y1) + l1*x1*(x1-1)^2*(6*x1^2-13*x1+4); + G2 = l0*(x2-y2) + 2*l1*x2; + patch = a0*l0 + a1*l1 - 1; +END; diff --git a/test/data/Bertini_examples/Chap14RealSets/FritzJohnInitial.input b/test/data/Bertini_examples/Chap14RealSets/FritzJohnInitial.input new file mode 100644 index 0000000..ba821d2 --- /dev/null +++ b/test/data/Bertini_examples/Chap14RealSets/FritzJohnInitial.input @@ -0,0 +1,17 @@ +% FritzJohnInitial.input + function F,G1,G2,patch; + variable_group x1,x2; + variable_group l0,l1; + constant y1,y2,eps,a0,a1; + + y1 = 0.5; + y2 = 0.8; + eps = 1.1 + 0.7*I; + a0 = -1.3; + a1 = 1.7; + + F = x2^2 + x1^2*(x1-1)^3*(x1-2) - eps; + G1 = l0*(x1-y1) + l1*x1*(x1-1)^2*(6*x1^2-13*x1+4); + G2 = l0*(x2-y2) + 2*l1*x2; + patch = a0*l0 + a1*l1 - 1; +END; diff --git a/test/data/Bertini_examples/Chap16ProjectionsOfSets/._.DS_Store b/test/data/Bertini_examples/Chap16ProjectionsOfSets/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap16ProjectionsOfSets/Discriminant.input b/test/data/Bertini_examples/Chap16ProjectionsOfSets/Discriminant.input new file mode 100644 index 0000000..873fb93 --- /dev/null +++ b/test/data/Bertini_examples/Chap16ProjectionsOfSets/Discriminant.input @@ -0,0 +1,23 @@ +% Discriminant.input +CONFIG + UserHomotopy:2; +END; +INPUT + function f1,f2,l1,l2; + variable_group a,b,c; + hom_variable_group x,z; + constant a1,b1,c1; + random gamma; + pathvariable T; + parameter t; + + t = T; + a1 = 1; + b1 = 2; + c1 = 1; + + f1 = a*x^2 + b*x*z + c*z^2; + f2 = 2*a*x + b*z; + l1 = (a - 3*c - 4)*(1 - t + gamma*t) - (a1 - 3*c1 - 4)*(1 - t); + l2 = (b + 3*c + 2)*(1 - t + gamma*t) - (b1 + 3*c1 + 2)*(1 - t); +END; diff --git a/test/data/Bertini_examples/Chap16ProjectionsOfSets/Enneper.input b/test/data/Bertini_examples/Chap16ProjectionsOfSets/Enneper.input new file mode 100644 index 0000000..dfd9568 --- /dev/null +++ b/test/data/Bertini_examples/Chap16ProjectionsOfSets/Enneper.input @@ -0,0 +1,12 @@ +% Enneper.input +CONFIG + TrackType:1; +END; +INPUT + function f1,f2,f3; + variable_group x,y,z,u,v; + + f1 = 3*x - u*(1 - u^2/3 + v^2); + f2 = 3*y + v*(1 - v^2/3 + u^2); + f3 = 3*z - (u^2 - v^2); +END; diff --git a/test/data/Bertini_examples/Chap1PolynomialSystems/._.DS_Store b/test/data/Bertini_examples/Chap1PolynomialSystems/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap1PolynomialSystems/._CircleAndYaxisC0.input b/test/data/Bertini_examples/Chap1PolynomialSystems/._CircleAndYaxisC0.input new file mode 100644 index 0000000000000000000000000000000000000000..549cf11e2dd488a39b7e1f02b09d5a383f433d1a GIT binary patch literal 1420 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(2Q|tX4pp0AK{lvvM#numCYw zKLPc_O`3%T=p$);$AW^K%;dz9%>2A!{gBj(64#W>61~KNg5l=hQU8pFz-S0yh5%|g isNovMV5b07B?BrGON)#0fov`YhX4OTIy+3Z2mt_VgcZC1 literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap1PolynomialSystems/CircleAndYaxisC0.input b/test/data/Bertini_examples/Chap1PolynomialSystems/CircleAndYaxisC0.input new file mode 100644 index 0000000..61b5416 --- /dev/null +++ b/test/data/Bertini_examples/Chap1PolynomialSystems/CircleAndYaxisC0.input @@ -0,0 +1,10 @@ + % CircleAndYaxisC0.input + function f,g; + variable_group x,y; + constant c; + + c = 0; + f = (x-c)^2+y^2-1; + g = x; + +END; diff --git a/test/data/Bertini_examples/Chap1PolynomialSystems/CircleAndYaxisC1.input b/test/data/Bertini_examples/Chap1PolynomialSystems/CircleAndYaxisC1.input new file mode 100644 index 0000000..b19c224 --- /dev/null +++ b/test/data/Bertini_examples/Chap1PolynomialSystems/CircleAndYaxisC1.input @@ -0,0 +1,10 @@ + % CircleAndYaxisC0.input + function f,g; + variable_group x,y; + constant c; + + c = 1; + f = (x-c)^2+y^2-1; + g = x; + +END; diff --git a/test/data/Bertini_examples/Chap1PolynomialSystems/degree10.input b/test/data/Bertini_examples/Chap1PolynomialSystems/degree10.input new file mode 100644 index 0000000..56fc1c7 --- /dev/null +++ b/test/data/Bertini_examples/Chap1PolynomialSystems/degree10.input @@ -0,0 +1,9 @@ +% degree10.input +CONFIG + FinalTol:1e-15; +END; +INPUT + variable_group z; + function p; + p = z^10 - 30*z^9 + 2; +END; diff --git a/test/data/Bertini_examples/Chap1PolynomialSystems/degree10eval.input b/test/data/Bertini_examples/Chap1PolynomialSystems/degree10eval.input new file mode 100644 index 0000000..e394990 --- /dev/null +++ b/test/data/Bertini_examples/Chap1PolynomialSystems/degree10eval.input @@ -0,0 +1,11 @@ +% degree10eval.input +CONFIG + TrackType:-4; + MPType:1; + Precision:128; +END; +INPUT + variable_group z; + function p; + p = z^10 - 30*z^9 + 2; +END; diff --git a/test/data/Bertini_examples/Chap1PolynomialSystems/degree10eval.points b/test/data/Bertini_examples/Chap1PolynomialSystems/degree10eval.points new file mode 100644 index 0000000..7898259 --- /dev/null +++ b/test/data/Bertini_examples/Chap1PolynomialSystems/degree10eval.points @@ -0,0 +1,22 @@ +6 + +30 0 + +30.00000000000021 -1.2e-12 + +7.422190004295883e-01 0.000000000000000e+00 + +2.999999999999990e+01 1.776356839400250e-15 + +0.742219000429588411304753220667e0 -0.107600627472146010258159776305e-26 + +0.299999999999998983894731417796e2 -0.208679331633159200994841978461e-22 + +% File: degree10eval.points +% some points for evaluating the degree10.input problem +% Try +% >> bertini degree10eval.input degree10eval.points +% z=30 is for illustration. +% z=30.00000000000021 + -1.2e-12*I is a solution approximated using FinalTol:1e-11; +% The next two are solutions approximated using FinalTol:1e-15; +% The last two are solutions approximated using FinalTol:1e-19; diff --git a/test/data/Bertini_examples/Chap1PolynomialSystems/input b/test/data/Bertini_examples/Chap1PolynomialSystems/input new file mode 100644 index 0000000..b79526d --- /dev/null +++ b/test/data/Bertini_examples/Chap1PolynomialSystems/input @@ -0,0 +1,7 @@ + %input: our first input file + variable_group x,y; + function f,g; + + f = x^2 - 1; + g = y^2 - 4; + END; diff --git a/test/data/Bertini_examples/Chap1PolynomialSystems/subfunctions.input b/test/data/Bertini_examples/Chap1PolynomialSystems/subfunctions.input new file mode 100644 index 0000000..cc93225 --- /dev/null +++ b/test/data/Bertini_examples/Chap1PolynomialSystems/subfunctions.input @@ -0,0 +1,9 @@ +% subfunctions.input +INPUT + variable_group z; + function p; + + a = z^3 + z + 1; + b = z^2 + 2; + p = a^4 - 5*b^3 + 6; +END; diff --git a/test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircle.input b/test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircle.input new file mode 100644 index 0000000..1625c6b --- /dev/null +++ b/test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircle.input @@ -0,0 +1,16 @@ +%AroundTheUnitCircle.input +CONFIG + UserHomotopy:1; +END; + +INPUT + variable z; + function H; + parameter q1,q2; + pathvariable t; + + q1 = cos(2*Pi*(1-t)); + q2 = sin(2*Pi*(1-t)); + s = q1 + I*q2; + H = z^2 - s; +END; diff --git a/test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircle.start b/test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircle.start new file mode 100644 index 0000000..322e153 --- /dev/null +++ b/test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircle.start @@ -0,0 +1,4 @@ +1 + +1 0; +%AroundTheUnitCircle.start diff --git a/test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircleAlt.input b/test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircleAlt.input new file mode 100644 index 0000000..0cf0866 --- /dev/null +++ b/test/data/Bertini_examples/Chap2BasicContinuation/AroundTheUnitCircleAlt.input @@ -0,0 +1,14 @@ +%AroundTheUnitCircleAlt.input +CONFIG + UserHomotopy:1; +END; + +INPUT + variable z; + function H; + parameter s; + pathvariable t; + + s = exp(2*Pi*I*(1-t)); + H = z^2 - s; +END; diff --git a/test/data/Bertini_examples/Chap4ProjectiveSpace/._.DS_Store b/test/data/Bertini_examples/Chap4ProjectiveSpace/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap4ProjectiveSpace/Eigenvalue2x2.input b/test/data/Bertini_examples/Chap4ProjectiveSpace/Eigenvalue2x2.input new file mode 100644 index 0000000..273795f --- /dev/null +++ b/test/data/Bertini_examples/Chap4ProjectiveSpace/Eigenvalue2x2.input @@ -0,0 +1,11 @@ +% Eigenvalue2x2.input +% A simple eigenvalue/eigenvector problem +% illustrating usage of hom_variable_group. +INPUT + function f1,f2; + variable_group lambda; + hom_variable_group v1,v2; + + f1 = (1-lambda)*v1 + 2*v2; + f2 = 3*v1 + (4-lambda)*v2; +END; diff --git a/test/data/Bertini_examples/Chap4ProjectiveSpace/GeneralizedEigenvalue.input b/test/data/Bertini_examples/Chap4ProjectiveSpace/GeneralizedEigenvalue.input new file mode 100644 index 0000000..b83279f --- /dev/null +++ b/test/data/Bertini_examples/Chap4ProjectiveSpace/GeneralizedEigenvalue.input @@ -0,0 +1,11 @@ +% GeneralizedEigenvalue.input +% Simple example of using two homogeneous groups. +% This is a 2x2 generalized eigenvalue problem. +INPUT + function f1,f2; + hom_variable_group v1,v2; + hom_variable_group mu,lambda; + + f1 = mu*(1*v1 + 2*v2) - lambda*( 4*v1 - 2*v2); + f2 = mu*(2*v1 + 4*v2) - lambda*(-2*v1 + 1*v2); +END; diff --git a/test/data/Bertini_examples/Chap4ProjectiveSpace/TwoCircles.input b/test/data/Bertini_examples/Chap4ProjectiveSpace/TwoCircles.input new file mode 100644 index 0000000..ac0c74d --- /dev/null +++ b/test/data/Bertini_examples/Chap4ProjectiveSpace/TwoCircles.input @@ -0,0 +1,13 @@ +% TwoCircles.input +% Intersection of two circles +CONFIG + % Force accurate determination of diverging paths + SecurityLevel:1; +END; +INPUT + function circle1, circle2; + variable_group x, y; + + circle1 = x^2 + y^2 - 1; + circle2 = (x-1)^2 + (y+1)^2 - 1; +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/._.DS_Store b/test/data/Bertini_examples/Chap5HomotopyTypes/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/LagrangePoints.input b/test/data/Bertini_examples/Chap5HomotopyTypes/LagrangePoints.input new file mode 100644 index 0000000..c168f35 --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/LagrangePoints.input @@ -0,0 +1,33 @@ +% LagrangePoints.input +% Equilibria for a 3rd small body rotating with two large +% ones in circular orbit +INPUT + function fma1,fma2,dist13,dist23,fma3x,fma3y; + % definition: w = omega^2 d12^3/(G m2) + % The remaining variables are nondimensionalized as + % ratio to d12. + variable_group w; + variable_group r1; + variable_group x,y,d13,d23; + constant mu; + + % choose value for the mass ratio + mu = 9; + + % the following eliminates r2 + r2 = 1-r1; + % f=ma on mass 1 + fma1 = w*r1 - 1; + % f=ma on mass 2 + fma2 = w*r2 - mu; + + % distance m1 to m3 + dist13 = (x-r1)^2 + y^2 - d13^2; + % distance m2 to m3 + dist23 = (x+r2)^2 + y^2 - d23^2; + + % f=ma on m3 + a = w*d13^3*d23^3; b1 = mu*d23^3; b2 = d13^3; + fma3x = a*x + b1*(r1-x) + b2*(-r2-x); + fma3y = a*y + b1*(-y) + b2*(-y); +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/LagrangePoints_regen.input b/test/data/Bertini_examples/Chap5HomotopyTypes/LagrangePoints_regen.input new file mode 100644 index 0000000..a17b7a9 --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/LagrangePoints_regen.input @@ -0,0 +1,37 @@ +% LagrangePoints_regen.input +% Equilibria for a 3rd small body rotating with two large +% ones in circular orbit +% Use regeneration instead of a basic 3-homogeneous homotopy +CONFIG + UseRegeneration:1; +END; +INPUT + function fma1,fma2,dist13,dist23,fma3x,fma3y; + % definition: w = omega^2 d12^3/(G m2) + % The remaining variables are nondimensionalized as + % ratio to d12. + variable_group w; + variable_group r1; + variable_group x,y,d13,d23; + constant mu; + + % choose value for the mass ratio + mu = 9; + + % the following eliminates r2 + r2 = 1-r1; + % f=ma on mass 1 + fma1 = w*r1 - 1; + % f=ma on mass 2 + fma2 = w*r2 - mu; + + % distance m1 to m3 + dist13 = (x-r1)^2 + y^2 - d13^2; + % distance m2 to m3 + dist23 = (x+r2)^2 + y^2 - d23^2; + + % f=ma on m3 + a = w*d13^3*d23^3; b1 = mu*d23^3; b2 = d13^3; + fma3x = a*x + b1*(r1-x) + b2*(-r2-x); + fma3y = a*y + b1*(-y) + b2*(-y); +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/SixR_2hom.input b/test/data/Bertini_examples/Chap5HomotopyTypes/SixR_2hom.input new file mode 100644 index 0000000..265cc49 --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/SixR_2hom.input @@ -0,0 +1,67 @@ +% SixR_2hom.input +% Random six-revolute serial link robot +% Variables in 2 groups +INPUT + % link lengths + random a1,a2,a3,a4,a5; + % link offsets + random d2,d3,d4,d5; + % twist cosines + random c1,c2,c3,c4,c5; + % endpoint position + random px,py,pz; + % joint 6 orientation + random z6x,z6y,z6z; + % joint 1 orientation (fixed) + constant z1x,z1y,z1z; + z1x=0; z1y=0; z1z=1; + + variable_group z2x,z2y,z2z, z4x,z4y,z4z; + variable_group z3x,z3y,z3z, z5x,z5y,z5z; + + function unit2, unit3, unit4, unit5; + function twist1, twist2, twist3, twist4, twist5; + function X,Y,Z; + + unit2 = z2x^2 + z2y^2 + z2z^2 -1; + unit3 = z3x^2 + z3y^2 + z3z^2 -1; + unit4 = z4x^2 + z4y^2 + z4z^2 -1; + unit5 = z5x^2 + z5y^2 + z5z^2 -1; + twist1 = z1x*z2x + z1y*z2y + z1z*z2z - c1; + twist2 = z2x*z3x + z2y*z3y + z2z*z3z - c2; + twist3 = z3x*z4x + z3y*z4y + z3z*z4z - c3; + twist4 = z4x*z5x + z4y*z5y + z4z*z5z - c4; + twist5 = z5x*z6x + z5y*z6y + z5z*z6z - c5; + % form cross products + x1x = z1y*z2z - z1z*z2y; + x2x = z2y*z3z - z2z*z3y; + x3x = z3y*z4z - z3z*z4y; + x4x = z4y*z5z - z4z*z5y; + x5x = z5y*z6z - z5z*z6y; + x1y = z1z*z2x - z1x*z2z; + x2y = z2z*z3x - z2x*z3z; + x3y = z3z*z4x - z3x*z4z; + x4y = z4z*z5x - z4x*z5z; + x5y = z5z*z6x - z5x*z6z; + x1z = z1x*z2y - z1y*z2x; + x2z = z2x*z3y - z2y*z3x; + x3z = z3x*z4y - z3y*z4x; + x4z = z4x*z5y - z4y*z5x; + x5z = z5x*z6y - z5y*z6x; + % position + X = a1*x1x + d2*z2x + + a2*x2x + d3*z3x + + a3*x3x + d4*z4x + + a4*x4x + d5*z5x + + a5*x5x - px; + Y = a1*x1y + d2*z2y + + a2*x2y + d3*z3y + + a3*x3y + d4*z4y + + a4*x4y + d5*z5y + + a5*x5y - py; + Z = a1*x1z + d2*z2z + + a2*x2z + d3*z3z + + a3*x3z + d4*z4z + + a4*x4z + d5*z5z + + a5*x5z - pz; +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/SixR_4hom.input b/test/data/Bertini_examples/Chap5HomotopyTypes/SixR_4hom.input new file mode 100644 index 0000000..5358115 --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/SixR_4hom.input @@ -0,0 +1,69 @@ +% SixR_4hom.input +% Random six-revolute serial link robot +% Variables in 4 groups +INPUT + % link lengths + random a1,a2,a3,a4,a5; + % link offsets + random d2,d3,d4,d5; + % twist cosines + random c1,c2,c3,c4,c5; + % endpoint position + random px,py,pz; + % joint 6 orientation + random z6x,z6y,z6z; + % joint 1 orientation (fixed) + constant z1x,z1y,z1z; + z1x=0; z1y=0; z1z=1; + + variable_group z2x,z2y,z2z; + variable_group z3x,z3y,z3z; + variable_group z4x,z4y,z4z; + variable_group z5x,z5y,z5z; + + function unit2, unit3, unit4, unit5; + function twist1, twist2, twist3, twist4, twist5; + function X,Y,Z; + + unit2 = z2x^2 + z2y^2 + z2z^2 -1; + unit3 = z3x^2 + z3y^2 + z3z^2 -1; + unit4 = z4x^2 + z4y^2 + z4z^2 -1; + unit5 = z5x^2 + z5y^2 + z5z^2 -1; + twist1 = z1x*z2x + z1y*z2y + z1z*z2z - c1; + twist2 = z2x*z3x + z2y*z3y + z2z*z3z - c2; + twist3 = z3x*z4x + z3y*z4y + z3z*z4z - c3; + twist4 = z4x*z5x + z4y*z5y + z4z*z5z - c4; + twist5 = z5x*z6x + z5y*z6y + z5z*z6z - c5; + % form cross products + x1x = z1y*z2z - z1z*z2y; + x2x = z2y*z3z - z2z*z3y; + x3x = z3y*z4z - z3z*z4y; + x4x = z4y*z5z - z4z*z5y; + x5x = z5y*z6z - z5z*z6y; + x1y = z1z*z2x - z1x*z2z; + x2y = z2z*z3x - z2x*z3z; + x3y = z3z*z4x - z3x*z4z; + x4y = z4z*z5x - z4x*z5z; + x5y = z5z*z6x - z5x*z6z; + x1z = z1x*z2y - z1y*z2x; + x2z = z2x*z3y - z2y*z3x; + x3z = z3x*z4y - z3y*z4x; + x4z = z4x*z5y - z4y*z5x; + x5z = z5x*z6y - z5y*z6x; + % position + X = a1*x1x + d2*z2x + + a2*x2x + d3*z3x + + a3*x3x + d4*z4x + + a4*x4x + d5*z5x + + a5*x5x - px; + Y = a1*x1y + d2*z2y + + a2*x2y + d3*z3y + + a3*x3y + d4*z4y + + a4*x4y + d5*z5y + + a5*x5y - py; + Z = a1*x1z + d2*z2z + + a2*x2z + d3*z3z + + a3*x3z + d4*z4z + + a4*x4z + d5*z5z + + a5*x5z - pz; +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/TwoHyperbolas_1Hom.input b/test/data/Bertini_examples/Chap5HomotopyTypes/TwoHyperbolas_1Hom.input new file mode 100644 index 0000000..1028d57 --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/TwoHyperbolas_1Hom.input @@ -0,0 +1,7 @@ +% TwoHyperbolas_1Hom.input +variable_group x,y; +function f1,f2; + +f1=x*y-1; +f2=x*y+x-y-1 ; +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/TwoHyperbolas_2Hom.input b/test/data/Bertini_examples/Chap5HomotopyTypes/TwoHyperbolas_2Hom.input new file mode 100644 index 0000000..155ae05 --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/TwoHyperbolas_2Hom.input @@ -0,0 +1,8 @@ +% TwoHyperbolas_2Hom.input +variable_group x; +variable_group y; +function f1,f2; + +f1=x*y-1; +f2=x*y+x-y-1 ; +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/TwoQuadrics_1hom.input b/test/data/Bertini_examples/Chap5HomotopyTypes/TwoQuadrics_1hom.input new file mode 100644 index 0000000..2f006c3 --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/TwoQuadrics_1hom.input @@ -0,0 +1,7 @@ +% TwoQuadrics_1hom.input +INPUT + function f1, f2; + variable_group x,y; + f1 = x*y - 1; + f2 = x^2 - 1; +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/TwoQuadrics_2hom.input b/test/data/Bertini_examples/Chap5HomotopyTypes/TwoQuadrics_2hom.input new file mode 100644 index 0000000..17e0b8d --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/TwoQuadrics_2hom.input @@ -0,0 +1,8 @@ +% TwoQuadrics_2hom.input +INPUT + function f1, f2; + variable_group x; + variable_group y; + f1 = x*y - 1; + f2 = x^2 - 1; +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/TwoSpheres_OneCone.input b/test/data/Bertini_examples/Chap5HomotopyTypes/TwoSpheres_OneCone.input new file mode 100644 index 0000000..b84d10c --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/TwoSpheres_OneCone.input @@ -0,0 +1,13 @@ +% TwoSpheres_OneCone.input +CONFIG + UseRegeneration:1; +END; +INPUT + function sphere1, sphere2, cone; + variable_group x,y,z; + random cx1,cy1,cz1,r1, cx2,cy2,cz2,r2, cx3,cy3,r3; + + sphere1 = (x-cx1)^2 + (y-cy1)^2 + (z-cz1)^2 - r1^2; + sphere2 = (x-cx2)^2 + (y-cy2)^2 + (z-cz2)^2 - r2^2; + cone = (x-z*cx3)^2 + (y-z*cy3)^2 - (z*r3)^2; +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen1group.input b/test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen1group.input new file mode 100644 index 0000000..8723bb4 --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen1group.input @@ -0,0 +1,149 @@ +% Nine-point path synthesis problem for four-bar linkages. +% All variables in one group +CONFIG + UseRegeneration:1; + TrackTolBeforeEG:1e-8; + TrackTolDuringEG:1e-8; + SliceTolBeforeEG:1e-8; + SliceTolDuringEG:1e-8; + SecurityMaxNorm:1e7; + EndpointFiniteThreshold:1e7; + PathTruncationThreshold:1e7; + SampleFactor:0.1; +END; + +INPUT + function f1,f2,f3,f4,f5,f6,f7,f8; + % Vectors a1,b1, a2,b2 in isotropic coordinates + variable_group a1,A1, b1,B1, a2,A2, b2,B2; + % (pk,PK), k=1,...,8, are the precision points in isotropic coords + random p1,P1, p2,P2, p3,P3, p4,P4, p5,P5, p6,P6, p7,P7, p8,P8; + + % These highest terms do not depend on the precision points: + n1 = A1*b1; + N1 = a1*B1; + n2 = A2*b2; + N2 = a2*B2; + % nN = |n N| = det[n1 N1; n2 N2] + nN = n1*N2 - n2*N1; + + % For each precision point we have an equation: + % f = |v u|*|v U| + |u U|^2, + % where + % v = [v1+n1+N1; v2+n2+N2], + % u = [w1-n1; w2-n2], U = [W1-N1; W2-N2]; + % Expand the expressions far enough so that the cancellation + % of the highest terms can be exposed. + % Repeat this template for k=1,...,8 + % v1k = pk*Pk - a1*Pk - A1*pk; + % v2k = pk*Pk - a2*Pk - A2*pk; + % w1k = b1*Pk; W1k = B1*pk; + % w2k = b2*Pk; W2k = B2*pk; + % These sums are the entries in v + % s1k = v1k + n1 + N1; + % s2k = v2k + n2 + N2; + % These are the lower-order terms (that do not cancel) + % vuLowk = s1k*w2k - s2k*w1k - v1k*n2 + v2k*n1; + % vULowk = s1k*W2k - s2k*W1k - v1k*N2 + v2k*N1; + % uULowk = w1k*W2k - w2k*W1k - w1k*N2 + w2k*N1 - n1*W2k + n2*W1k; + % Finally, form f, with degree 8 terms cancelled out. + % (highest terms are |n N|*|N n| + |n N|^2 = 0) + % fk = vuLowk*vULowk - vuLowk*nN + vULowk*nN + uULowk^2 + 2*uULowk*nN; + + % k=1 + v11 = p1*P1 - a1*P1 - A1*p1; + v21 = p1*P1 - a2*P1 - A2*p1; + w11 = b1*P1; W11 = B1*p1; + w21 = b2*P1; W21 = B2*p1; + s11 = v11 + n1 + N1; + s21 = v21 + n2 + N2; + vuLow1 = s11*w21 - s21*w11 - v11*n2 + v21*n1; + vULow1 = s11*W21 - s21*W11 - v11*N2 + v21*N1; + uULow1 = w11*W21 - w21*W11 - w11*N2 + w21*N1 - n1*W21 + n2*W11; + f1 = vuLow1*vULow1 - vuLow1*nN + vULow1*nN + uULow1^2 + 2*uULow1*nN; + + % k=2 + v12 = p2*P2 - a1*P2 - A1*p2; + v22 = p2*P2 - a2*P2 - A2*p2; + w12 = b1*P2; W12 = B1*p2; + w22 = b2*P2; W22 = B2*p2; + s12 = v12 + n1 + N1; + s22 = v22 + n2 + N2; + vuLow2 = s12*w22 - s22*w12 - v12*n2 + v22*n1; + vULow2 = s12*W22 - s22*W12 - v12*N2 + v22*N1; + uULow2 = w12*W22 - w22*W12 - w12*N2 + w22*N1 - n1*W22 + n2*W12; + f2 = vuLow2*vULow2 - vuLow2*nN + vULow2*nN + uULow2^2 + 2*uULow2*nN; + + % k=3 + v13 = p3*P3 - a1*P3 - A1*p3; + v23 = p3*P3 - a2*P3 - A2*p3; + w13 = b1*P3; W13 = B1*p3; + w23 = b2*P3; W23 = B2*p3; + s13 = v13 + n1 + N1; + s23 = v23 + n2 + N2; + vuLow3 = s13*w23 - s23*w13 - v13*n2 + v23*n1; + vULow3 = s13*W23 - s23*W13 - v13*N2 + v23*N1; + uULow3 = w13*W23 - w23*W13 - w13*N2 + w23*N1 - n1*W23 + n2*W13; + f3 = vuLow3*vULow3 - vuLow3*nN + vULow3*nN + uULow3^2 + 2*uULow3*nN; + + % k=4 + v14 = p4*P4 - a1*P4 - A1*p4; + v24 = p4*P4 - a2*P4 - A2*p4; + w14 = b1*P4; W14 = B1*p4; + w24 = b2*P4; W24 = B2*p4; + s14 = v14 + n1 + N1; + s24 = v24 + n2 + N2; + vuLow4 = s14*w24 - s24*w14 - v14*n2 + v24*n1; + vULow4 = s14*W24 - s24*W14 - v14*N2 + v24*N1; + uULow4 = w14*W24 - w24*W14 - w14*N2 + w24*N1 - n1*W24 + n2*W14; + f4 = vuLow4*vULow4 - vuLow4*nN + vULow4*nN + uULow4^2 + 2*uULow4*nN; + + % k=5 + v15 = p5*P5 - a1*P5 - A1*p5; + v25 = p5*P5 - a2*P5 - A2*p5; + w15 = b1*P5; W15 = B1*p5; + w25 = b2*P5; W25 = B2*p5; + s15 = v15 + n1 + N1; + s25 = v25 + n2 + N2; + vuLow5 = s15*w25 - s25*w15 - v15*n2 + v25*n1; + vULow5 = s15*W25 - s25*W15 - v15*N2 + v25*N1; + uULow5 = w15*W25 - w25*W15 - w15*N2 + w25*N1 - n1*W25 + n2*W15; + f5 = vuLow5*vULow5 - vuLow5*nN + vULow5*nN + uULow5^2 + 2*uULow5*nN; + + % k=6 + v16 = p6*P6 - a1*P6 - A1*p6; + v26 = p6*P6 - a2*P6 - A2*p6; + w16 = b1*P6; W16 = B1*p6; + w26 = b2*P6; W26 = B2*p6; + s16 = v16 + n1 + N1; + s26 = v26 + n2 + N2; + vuLow6 = s16*w26 - s26*w16 - v16*n2 + v26*n1; + vULow6 = s16*W26 - s26*W16 - v16*N2 + v26*N1; + uULow6 = w16*W26 - w26*W16 - w16*N2 + w26*N1 - n1*W26 + n2*W16; + f6 = vuLow6*vULow6 - vuLow6*nN + vULow6*nN + uULow6^2 + 2*uULow6*nN; + + % k=7 + v17 = p7*P7 - a1*P7 - A1*p7; + v27 = p7*P7 - a2*P7 - A2*p7; + w17 = b1*P7; W17 = B1*p7; + w27 = b2*P7; W27 = B2*p7; + s17 = v17 + n1 + N1; + s27 = v27 + n2 + N2; + vuLow7 = s17*w27 - s27*w17 - v17*n2 + v27*n1; + vULow7 = s17*W27 - s27*W17 - v17*N2 + v27*N1; + uULow7 = w17*W27 - w27*W17 - w17*N2 + w27*N1 - n1*W27 + n2*W17; + f7 = vuLow7*vULow7 - vuLow7*nN + vULow7*nN + uULow7^2 + 2*uULow7*nN; + + % k=8 + v18 = p8*P8 - a1*P8 - A1*p8; + v28 = p8*P8 - a2*P8 - A2*p8; + w18 = b1*P8; W18 = B1*p8; + w28 = b2*P8; W28 = B2*p8; + s18 = v18 + n1 + N1; + s28 = v28 + n2 + N2; + vuLow8 = s18*w28 - s28*w18 - v18*n2 + v28*n1; + vULow8 = s18*W28 - s28*W18 - v18*N2 + v28*N1; + uULow8 = w18*W28 - w28*W18 - w18*N2 + w28*N1 - n1*W28 + n2*W18; + f8 = vuLow8*vULow8 - vuLow8*nN + vULow8*nN + uULow8^2 + 2*uULow8*nN; + +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen2groups.input b/test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen2groups.input new file mode 100644 index 0000000..d3fb80a --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen2groups.input @@ -0,0 +1,150 @@ +% Nine-point path synthesis problem for four-bar linkages. +% Variables in 2 groups +CONFIG + UseRegeneration:1; + TrackTolBeforeEG:1e-8; + TrackTolDuringEG:1e-8; + SliceTolBeforeEG:1e-8; + SliceTolDuringEG:1e-8; + SecurityMaxNorm:1e7; + EndpointFiniteThreshold:1e7; + PathTruncationThreshold:1e7; + SampleFactor:0.1; +END; + +INPUT + function f1,f2,f3,f4,f5,f6,f7,f8; + % Vectors a1,b1, a2,b2 in isotropic coordinates + variable_group a1,A1, b1,B1; + variable_group a2,A2, b2,B2; + % (pk,PK), k=1,...,8, are the precision points in isotropic coords + random p1,P1, p2,P2, p3,P3, p4,P4, p5,P5, p6,P6, p7,P7, p8,P8; + + % These highest terms do not depend on the precision points: + n1 = A1*b1; + N1 = a1*B1; + n2 = A2*b2; + N2 = a2*B2; + % nN = |n N| = det[n1 N1; n2 N2] + nN = n1*N2 - n2*N1; + + % For each precision point we have an equation: + % f = |v u|*|v U| + |u U|^2, + % where + % v = [v1+n1+N1; v2+n2+N2], + % u = [w1-n1; w2-n2], U = [W1-N1; W2-N2]; + % Expand the expressions far enough so that the cancellation + % of the highest terms can be exposed. + % Repeat this template for k=1,...,8 + % v1k = pk*Pk - a1*Pk - A1*pk; + % v2k = pk*Pk - a2*Pk - A2*pk; + % w1k = b1*Pk; W1k = B1*pk; + % w2k = b2*Pk; W2k = B2*pk; + % These sums are the entries in v + % s1k = v1k + n1 + N1; + % s2k = v2k + n2 + N2; + % These are the lower-order terms (that do not cancel) + % vuLowk = s1k*w2k - s2k*w1k - v1k*n2 + v2k*n1; + % vULowk = s1k*W2k - s2k*W1k - v1k*N2 + v2k*N1; + % uULowk = w1k*W2k - w2k*W1k - w1k*N2 + w2k*N1 - n1*W2k + n2*W1k; + % Finally, form f, with degree 8 terms cancelled out. + % (highest terms are |n N|*|N n| + |n N|^2 = 0) + % fk = vuLowk*vULowk - vuLowk*nN + vULowk*nN + uULowk^2 + 2*uULowk*nN; + + % k=1 + v11 = p1*P1 - a1*P1 - A1*p1; + v21 = p1*P1 - a2*P1 - A2*p1; + w11 = b1*P1; W11 = B1*p1; + w21 = b2*P1; W21 = B2*p1; + s11 = v11 + n1 + N1; + s21 = v21 + n2 + N2; + vuLow1 = s11*w21 - s21*w11 - v11*n2 + v21*n1; + vULow1 = s11*W21 - s21*W11 - v11*N2 + v21*N1; + uULow1 = w11*W21 - w21*W11 - w11*N2 + w21*N1 - n1*W21 + n2*W11; + f1 = vuLow1*vULow1 - vuLow1*nN + vULow1*nN + uULow1^2 + 2*uULow1*nN; + + % k=2 + v12 = p2*P2 - a1*P2 - A1*p2; + v22 = p2*P2 - a2*P2 - A2*p2; + w12 = b1*P2; W12 = B1*p2; + w22 = b2*P2; W22 = B2*p2; + s12 = v12 + n1 + N1; + s22 = v22 + n2 + N2; + vuLow2 = s12*w22 - s22*w12 - v12*n2 + v22*n1; + vULow2 = s12*W22 - s22*W12 - v12*N2 + v22*N1; + uULow2 = w12*W22 - w22*W12 - w12*N2 + w22*N1 - n1*W22 + n2*W12; + f2 = vuLow2*vULow2 - vuLow2*nN + vULow2*nN + uULow2^2 + 2*uULow2*nN; + + % k=3 + v13 = p3*P3 - a1*P3 - A1*p3; + v23 = p3*P3 - a2*P3 - A2*p3; + w13 = b1*P3; W13 = B1*p3; + w23 = b2*P3; W23 = B2*p3; + s13 = v13 + n1 + N1; + s23 = v23 + n2 + N2; + vuLow3 = s13*w23 - s23*w13 - v13*n2 + v23*n1; + vULow3 = s13*W23 - s23*W13 - v13*N2 + v23*N1; + uULow3 = w13*W23 - w23*W13 - w13*N2 + w23*N1 - n1*W23 + n2*W13; + f3 = vuLow3*vULow3 - vuLow3*nN + vULow3*nN + uULow3^2 + 2*uULow3*nN; + + % k=4 + v14 = p4*P4 - a1*P4 - A1*p4; + v24 = p4*P4 - a2*P4 - A2*p4; + w14 = b1*P4; W14 = B1*p4; + w24 = b2*P4; W24 = B2*p4; + s14 = v14 + n1 + N1; + s24 = v24 + n2 + N2; + vuLow4 = s14*w24 - s24*w14 - v14*n2 + v24*n1; + vULow4 = s14*W24 - s24*W14 - v14*N2 + v24*N1; + uULow4 = w14*W24 - w24*W14 - w14*N2 + w24*N1 - n1*W24 + n2*W14; + f4 = vuLow4*vULow4 - vuLow4*nN + vULow4*nN + uULow4^2 + 2*uULow4*nN; + + % k=5 + v15 = p5*P5 - a1*P5 - A1*p5; + v25 = p5*P5 - a2*P5 - A2*p5; + w15 = b1*P5; W15 = B1*p5; + w25 = b2*P5; W25 = B2*p5; + s15 = v15 + n1 + N1; + s25 = v25 + n2 + N2; + vuLow5 = s15*w25 - s25*w15 - v15*n2 + v25*n1; + vULow5 = s15*W25 - s25*W15 - v15*N2 + v25*N1; + uULow5 = w15*W25 - w25*W15 - w15*N2 + w25*N1 - n1*W25 + n2*W15; + f5 = vuLow5*vULow5 - vuLow5*nN + vULow5*nN + uULow5^2 + 2*uULow5*nN; + + % k=6 + v16 = p6*P6 - a1*P6 - A1*p6; + v26 = p6*P6 - a2*P6 - A2*p6; + w16 = b1*P6; W16 = B1*p6; + w26 = b2*P6; W26 = B2*p6; + s16 = v16 + n1 + N1; + s26 = v26 + n2 + N2; + vuLow6 = s16*w26 - s26*w16 - v16*n2 + v26*n1; + vULow6 = s16*W26 - s26*W16 - v16*N2 + v26*N1; + uULow6 = w16*W26 - w26*W16 - w16*N2 + w26*N1 - n1*W26 + n2*W16; + f6 = vuLow6*vULow6 - vuLow6*nN + vULow6*nN + uULow6^2 + 2*uULow6*nN; + + % k=7 + v17 = p7*P7 - a1*P7 - A1*p7; + v27 = p7*P7 - a2*P7 - A2*p7; + w17 = b1*P7; W17 = B1*p7; + w27 = b2*P7; W27 = B2*p7; + s17 = v17 + n1 + N1; + s27 = v27 + n2 + N2; + vuLow7 = s17*w27 - s27*w17 - v17*n2 + v27*n1; + vULow7 = s17*W27 - s27*W17 - v17*N2 + v27*N1; + uULow7 = w17*W27 - w27*W17 - w17*N2 + w27*N1 - n1*W27 + n2*W17; + f7 = vuLow7*vULow7 - vuLow7*nN + vULow7*nN + uULow7^2 + 2*uULow7*nN; + + % k=8 + v18 = p8*P8 - a1*P8 - A1*p8; + v28 = p8*P8 - a2*P8 - A2*p8; + w18 = b1*P8; W18 = B1*p8; + w28 = b2*P8; W28 = B2*p8; + s18 = v18 + n1 + N1; + s28 = v28 + n2 + N2; + vuLow8 = s18*w28 - s28*w18 - v18*n2 + v28*n1; + vULow8 = s18*W28 - s28*W18 - v18*N2 + v28*N1; + uULow8 = w18*W28 - w28*W18 - w18*N2 + w28*N1 - n1*W28 + n2*W18; + f8 = vuLow8*vULow8 - vuLow8*nN + vULow8*nN + uULow8^2 + 2*uULow8*nN; + +END; diff --git a/test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen4groups.input b/test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen4groups.input new file mode 100644 index 0000000..2308a72 --- /dev/null +++ b/test/data/Bertini_examples/Chap5HomotopyTypes/ninepoint_regen4groups.input @@ -0,0 +1,152 @@ +% Nine-point path synthesis problem for four-bar linkages. +% Variables in 4 groups +CONFIG + UseRegeneration:1; + TrackTolBeforeEG:1e-8; + TrackTolDuringEG:1e-8; + SliceTolBeforeEG:1e-8; + SliceTolDuringEG:1e-8; + SecurityMaxNorm:1e7; + EndpointFiniteThreshold:1e7; + PathTruncationThreshold:1e7; + SampleFactor:0.1; +END; + +INPUT + function f1,f2,f3,f4,f5,f6,f7,f8; + % Vectors a1,b1, a2,b2 in isotropic coordinates + variable_group a1,b1; + variable_group a2,b2; + variable_group A1,B1; + variable_group A2,B2; + % (pk,PK), k=1,...,8, are the precision points in isotropic coords + random p1,P1, p2,P2, p3,P3, p4,P4, p5,P5, p6,P6, p7,P7, p8,P8; + + % These highest terms do not depend on the precision points: + n1 = A1*b1; + N1 = a1*B1; + n2 = A2*b2; + N2 = a2*B2; + % nN = |n N| = det[n1 N1; n2 N2] + nN = n1*N2 - n2*N1; + + % For each precision point we have an equation: + % f = |v u|*|v U| + |u U|^2, + % where + % v = [v1+n1+N1; v2+n2+N2], + % u = [w1-n1; w2-n2], U = [W1-N1; W2-N2]; + % Expand the expressions far enough so that the cancellation + % of the highest terms can be exposed. + % Repeat this template for k=1,...,8 + % v1k = pk*Pk - a1*Pk - A1*pk; + % v2k = pk*Pk - a2*Pk - A2*pk; + % w1k = b1*Pk; W1k = B1*pk; + % w2k = b2*Pk; W2k = B2*pk; + % These sums are the entries in v + % s1k = v1k + n1 + N1; + % s2k = v2k + n2 + N2; + % These are the lower-order terms (that do not cancel) + % vuLowk = s1k*w2k - s2k*w1k - v1k*n2 + v2k*n1; + % vULowk = s1k*W2k - s2k*W1k - v1k*N2 + v2k*N1; + % uULowk = w1k*W2k - w2k*W1k - w1k*N2 + w2k*N1 - n1*W2k + n2*W1k; + % Finally, form f, with degree 8 terms cancelled out. + % (highest terms are |n N|*|N n| + |n N|^2 = 0) + % fk = vuLowk*vULowk - vuLowk*nN + vULowk*nN + uULowk^2 + 2*uULowk*nN; + + % k=1 + v11 = p1*P1 - a1*P1 - A1*p1; + v21 = p1*P1 - a2*P1 - A2*p1; + w11 = b1*P1; W11 = B1*p1; + w21 = b2*P1; W21 = B2*p1; + s11 = v11 + n1 + N1; + s21 = v21 + n2 + N2; + vuLow1 = s11*w21 - s21*w11 - v11*n2 + v21*n1; + vULow1 = s11*W21 - s21*W11 - v11*N2 + v21*N1; + uULow1 = w11*W21 - w21*W11 - w11*N2 + w21*N1 - n1*W21 + n2*W11; + f1 = vuLow1*vULow1 - vuLow1*nN + vULow1*nN + uULow1^2 + 2*uULow1*nN; + + % k=2 + v12 = p2*P2 - a1*P2 - A1*p2; + v22 = p2*P2 - a2*P2 - A2*p2; + w12 = b1*P2; W12 = B1*p2; + w22 = b2*P2; W22 = B2*p2; + s12 = v12 + n1 + N1; + s22 = v22 + n2 + N2; + vuLow2 = s12*w22 - s22*w12 - v12*n2 + v22*n1; + vULow2 = s12*W22 - s22*W12 - v12*N2 + v22*N1; + uULow2 = w12*W22 - w22*W12 - w12*N2 + w22*N1 - n1*W22 + n2*W12; + f2 = vuLow2*vULow2 - vuLow2*nN + vULow2*nN + uULow2^2 + 2*uULow2*nN; + + % k=3 + v13 = p3*P3 - a1*P3 - A1*p3; + v23 = p3*P3 - a2*P3 - A2*p3; + w13 = b1*P3; W13 = B1*p3; + w23 = b2*P3; W23 = B2*p3; + s13 = v13 + n1 + N1; + s23 = v23 + n2 + N2; + vuLow3 = s13*w23 - s23*w13 - v13*n2 + v23*n1; + vULow3 = s13*W23 - s23*W13 - v13*N2 + v23*N1; + uULow3 = w13*W23 - w23*W13 - w13*N2 + w23*N1 - n1*W23 + n2*W13; + f3 = vuLow3*vULow3 - vuLow3*nN + vULow3*nN + uULow3^2 + 2*uULow3*nN; + + % k=4 + v14 = p4*P4 - a1*P4 - A1*p4; + v24 = p4*P4 - a2*P4 - A2*p4; + w14 = b1*P4; W14 = B1*p4; + w24 = b2*P4; W24 = B2*p4; + s14 = v14 + n1 + N1; + s24 = v24 + n2 + N2; + vuLow4 = s14*w24 - s24*w14 - v14*n2 + v24*n1; + vULow4 = s14*W24 - s24*W14 - v14*N2 + v24*N1; + uULow4 = w14*W24 - w24*W14 - w14*N2 + w24*N1 - n1*W24 + n2*W14; + f4 = vuLow4*vULow4 - vuLow4*nN + vULow4*nN + uULow4^2 + 2*uULow4*nN; + + % k=5 + v15 = p5*P5 - a1*P5 - A1*p5; + v25 = p5*P5 - a2*P5 - A2*p5; + w15 = b1*P5; W15 = B1*p5; + w25 = b2*P5; W25 = B2*p5; + s15 = v15 + n1 + N1; + s25 = v25 + n2 + N2; + vuLow5 = s15*w25 - s25*w15 - v15*n2 + v25*n1; + vULow5 = s15*W25 - s25*W15 - v15*N2 + v25*N1; + uULow5 = w15*W25 - w25*W15 - w15*N2 + w25*N1 - n1*W25 + n2*W15; + f5 = vuLow5*vULow5 - vuLow5*nN + vULow5*nN + uULow5^2 + 2*uULow5*nN; + + % k=6 + v16 = p6*P6 - a1*P6 - A1*p6; + v26 = p6*P6 - a2*P6 - A2*p6; + w16 = b1*P6; W16 = B1*p6; + w26 = b2*P6; W26 = B2*p6; + s16 = v16 + n1 + N1; + s26 = v26 + n2 + N2; + vuLow6 = s16*w26 - s26*w16 - v16*n2 + v26*n1; + vULow6 = s16*W26 - s26*W16 - v16*N2 + v26*N1; + uULow6 = w16*W26 - w26*W16 - w16*N2 + w26*N1 - n1*W26 + n2*W16; + f6 = vuLow6*vULow6 - vuLow6*nN + vULow6*nN + uULow6^2 + 2*uULow6*nN; + + % k=7 + v17 = p7*P7 - a1*P7 - A1*p7; + v27 = p7*P7 - a2*P7 - A2*p7; + w17 = b1*P7; W17 = B1*p7; + w27 = b2*P7; W27 = B2*p7; + s17 = v17 + n1 + N1; + s27 = v27 + n2 + N2; + vuLow7 = s17*w27 - s27*w17 - v17*n2 + v27*n1; + vULow7 = s17*W27 - s27*W17 - v17*N2 + v27*N1; + uULow7 = w17*W27 - w27*W17 - w17*N2 + w27*N1 - n1*W27 + n2*W17; + f7 = vuLow7*vULow7 - vuLow7*nN + vULow7*nN + uULow7^2 + 2*uULow7*nN; + + % k=8 + v18 = p8*P8 - a1*P8 - A1*p8; + v28 = p8*P8 - a2*P8 - A2*p8; + w18 = b1*P8; W18 = B1*p8; + w28 = b2*P8; W28 = B2*p8; + s18 = v18 + n1 + N1; + s28 = v28 + n2 + N2; + vuLow8 = s18*w28 - s28*w18 - v18*n2 + v28*n1; + vULow8 = s18*W28 - s28*W18 - v18*N2 + v28*N1; + uULow8 = w18*W28 - w28*W18 - w18*N2 + w28*N1 - n1*W28 + n2*W18; + f8 = vuLow8*vULow8 - vuLow8*nN + vULow8*nN + uULow8^2 + 2*uULow8*nN; + +END; diff --git a/test/data/Bertini_examples/Chap6ParameterHomotopy/._.DS_Store b/test/data/Bertini_examples/Chap6ParameterHomotopy/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap6ParameterHomotopy/LagrangePoints.input b/test/data/Bertini_examples/Chap6ParameterHomotopy/LagrangePoints.input new file mode 100644 index 0000000..c168f35 --- /dev/null +++ b/test/data/Bertini_examples/Chap6ParameterHomotopy/LagrangePoints.input @@ -0,0 +1,33 @@ +% LagrangePoints.input +% Equilibria for a 3rd small body rotating with two large +% ones in circular orbit +INPUT + function fma1,fma2,dist13,dist23,fma3x,fma3y; + % definition: w = omega^2 d12^3/(G m2) + % The remaining variables are nondimensionalized as + % ratio to d12. + variable_group w; + variable_group r1; + variable_group x,y,d13,d23; + constant mu; + + % choose value for the mass ratio + mu = 9; + + % the following eliminates r2 + r2 = 1-r1; + % f=ma on mass 1 + fma1 = w*r1 - 1; + % f=ma on mass 2 + fma2 = w*r2 - mu; + + % distance m1 to m3 + dist13 = (x-r1)^2 + y^2 - d13^2; + % distance m2 to m3 + dist23 = (x+r2)^2 + y^2 - d23^2; + + % f=ma on m3 + a = w*d13^3*d23^3; b1 = mu*d23^3; b2 = d13^3; + fma3x = a*x + b1*(r1-x) + b2*(-r2-x); + fma3y = a*y + b1*(-y) + b2*(-y); +END; diff --git a/test/data/Bertini_examples/Chap6ParameterHomotopy/LagrangePoints_parameter.input b/test/data/Bertini_examples/Chap6ParameterHomotopy/LagrangePoints_parameter.input new file mode 100644 index 0000000..74e7a35 --- /dev/null +++ b/test/data/Bertini_examples/Chap6ParameterHomotopy/LagrangePoints_parameter.input @@ -0,0 +1,35 @@ +% Lagrange Points problem +% Equilibria for a 3rd small body rotating with two large +% ones in circular orbit +% +% Set up for parameter homotopy +CONFIG + ParameterHomotopy:1; % change to 2 after ab initio run is done +END; +INPUT + function fma1,fma2,dist13,dist23,fma3x,fma3y; + % definition: w = omega^2 d12^3/(G m2) + % The remaining variables are nondimensionalized as + % ratio to d12. + variable_group w; + variable_group r1; + variable_group x,y,d13,d23; + parameter mu; + + % the following eliminates r2 + r2 = 1-r1; + % f=ma on mass 1 + fma1 = w*r1 - 1; + % f=ma on mass 2 + fma2 = w*r2 - mu; + + % distance m1 to m3 + dist13 = (x-r1)^2 + y^2 - d13^2; + % distance m2 to m3 + dist23 = (x+r2)^2 + y^2 - d23^2; + + % f=ma on m3 + a = w*d13^3*d23^3; b1 = mu*d23^3; b2 = d13^3; + fma3x = a*x + b1*(r1-x) + b2*(-r2-x); + fma3y = a*y + b1*(-y) + b2*(-y); +END; diff --git a/test/data/Bertini_examples/Chap6ParameterHomotopy/SixR_parameter.input b/test/data/Bertini_examples/Chap6ParameterHomotopy/SixR_parameter.input new file mode 100644 index 0000000..6a618fb --- /dev/null +++ b/test/data/Bertini_examples/Chap6ParameterHomotopy/SixR_parameter.input @@ -0,0 +1,72 @@ +% SixR_parameter.input +% +% Input file for solving 6R inverse kinematics by parameter homotopy +% +CONFIG + % Set to 1 for ab initio run, change to 2 for parameter runs. + ParameterHomotopy:1; +END +INPUT + % link lengths + parameter a1,a2,a3,a4,a5; + % link offsets + parameter d2,d3,d4,d5; + % twist cosines + parameter c1,c2,c3,c4,c5; + % endpoint position + parameter px,py,pz; + % joint 6 orientation + parameter z6x,z6y,z6z; + % joint 1 orientation (fixed) + constant z1x,z1y,z1z; + z1x=0; z1y=0; z1z=1; + + variable_group z2x,z2y,z2z, z4x,z4y,z4z; + variable_group z3x,z3y,z3z, z5x,z5y,z5z; + + function unit2, unit3, unit4, unit5; + function twist1, twist2, twist3, twist4, twist5; + function X,Y,Z; + + unit2 = z2x^2 + z2y^2 + z2z^2 -1; + unit3 = z3x^2 + z3y^2 + z3z^2 -1; + unit4 = z4x^2 + z4y^2 + z4z^2 -1; + unit5 = z5x^2 + z5y^2 + z5z^2 -1; + twist1 = z1x*z2x + z1y*z2y + z1z*z2z - c1; + twist2 = z2x*z3x + z2y*z3y + z2z*z3z - c2; + twist3 = z3x*z4x + z3y*z4y + z3z*z4z - c3; + twist4 = z4x*z5x + z4y*z5y + z4z*z5z - c4; + twist5 = z5x*z6x + z5y*z6y + z5z*z6z - c5; + % form cross products + x1x = z1y*z2z - z1z*z2y; + x2x = z2y*z3z - z2z*z3y; + x3x = z3y*z4z - z3z*z4y; + x4x = z4y*z5z - z4z*z5y; + x5x = z5y*z6z - z5z*z6y; + x1y = z1z*z2x - z1x*z2z; + x2y = z2z*z3x - z2x*z3z; + x3y = z3z*z4x - z3x*z4z; + x4y = z4z*z5x - z4x*z5z; + x5y = z5z*z6x - z5x*z6z; + x1z = z1x*z2y - z1y*z2x; + x2z = z2x*z3y - z2y*z3x; + x3z = z3x*z4y - z3y*z4x; + x4z = z4x*z5y - z4y*z5x; + x5z = z5x*z6y - z5y*z6x; + % position + X = a1*x1x + d2*z2x + + a2*x2x + d3*z3x + + a3*x3x + d4*z4x + + a4*x4x + d5*z5x + + a5*x5x - px; + Y = a1*x1y + d2*z2y + + a2*x2y + d3*z3y + + a3*x3y + d4*z4y + + a4*x4y + d5*z5y + + a5*x5y - py; + Z = a1*x1z + d2*z2z + + a2*x2z + d3*z3z + + a3*x3z + d4*z4z + + a4*x4z + d5*z5z + + a5*x5z - pz; +END; diff --git a/test/data/Bertini_examples/Chap6ParameterHomotopy/StewartGough.input b/test/data/Bertini_examples/Chap6ParameterHomotopy/StewartGough.input new file mode 100644 index 0000000..957e1fc --- /dev/null +++ b/test/data/Bertini_examples/Chap6ParameterHomotopy/StewartGough.input @@ -0,0 +1,125 @@ +% Stewart-Gough platform forward kinematics +% +% This is the general case. +CONFIG + % Set to 1 for ab initio run, change to 2 for parameter runs. + ParameterHomotopy:1; +END + + +INPUT + % The two rigid bodies have 6 point pairs at known distances. + % 6 points on the stationary rigid body + parameter a1x,a1y,a1z, a2x,a2y,a2z, a3x,a3y,a3z, a4x,a4y,a4z, a5x,a5y,a5z, a6x,a6y,a6z; + % 6 points on the moving rigid body + parameter b1x,b1y,b1z, b2x,b2y,b2z, b3x,b3y,b3z, b4x,b4y,b4z, b5x,b5y,b5z, b6x,b6y,b6z; + % squared distances between point pairs + parameter d1,d2,d3,d4,d5,d6; + + % These will be the squared distance functions + function f1,f2,f3,f4,f5,f6; + % The Study quadric + function Study; + + % Use Study coordinates for the position & orientation of the moving body. + hom_variable_group e0,e1,e2,e3,g0,g1,g2,g3; + + % Let X be the 4x4 representation of quaternion (x0,x1,x2,x3) + % So + % X = [ x0 -x1 -x2 -x3 + % x1 x0 -x3 x2 + % x2 x3 x0 -x1 + % x3 -x2 x1 x0 ] + % Treat vector (v1,v2,v3) as quaternion (0,v1,v2,v3). + % We also say that Re(x) = x0 or equivalently, Re(X) = x0*I. + + % Quaternions obey the relation X*X' = |(x0,x1,x2,x3)|^2 = |X|^2 + % Let ee = E*E', gg = G*G': + ee = e0^2 + e1^2 + e2^2 +e3^2; + gg = g0^2 + g1^2 + g2^2 +g3^2; + + % After transformation, a point b = (b1,b2,b3) becomes + % Transf(b) = (E*B*E' + G*E')/ee + % with the Study quadric side condition of + % Study = Re(G*E') = 0 + Study = g0*e0 + g1*e1 + g2*e2 + g3*e3; + + % Accordingly, the governing equations are the squared distance relations + % (*) d = | (E*B*E' + G*E')/ee - A |^2 + % = [ (E*B*E' + G*E')/ee - A ]*[ (E*B'*E' + E*G')/ee - A'] + % After expanding this, several instances of E*E' = ee*I appear. After + % simplifying ee/ee = 1 (cases of ee=0 are meaningless) and then + % clearing the denominator by multiplying by ee, (*) becomes + % a quadric relation in E,G, with A,B,d considered constants. + % We apply this 6 times for d_i, a_i, b_i. + + % We simplify (*) with some vector algebra, where the following + % terms appear: + R11 = e0^2+e1^2-e2^2-e3^2; + R12 = 2*(-e0*e3+e1*e2); + R13 = 2*( e0*e2+e1*e3); + R21 = 2*( e0*e3+e2*e1); + R22 = e0^2-e1^2+e2^2-e3^2; + R23 = 2*(-e0*e1+e2*e3); + R31 = 2*(-e0*e2+e3*e1); + R32 = 2*( e0*e1+e3*e2); + R33 = e0^2-e1^2-e2^2+e3^2; + u1 = g0*e1 - e0*g1; + u2 = g0*e2 - e0*g2; + u3 = g0*e3 - e0*g3; + v1 = g2*e3 - g3*e2; + v2 = g3*e1 - g1*e3; + v3 = g1*e2 - g2*e1; + + % Now, we form the 6 distance equations. + % Write it in terms of J, then substitute J = 1,...,6 +% fJ = (aJx^2+aJy^2+aJz^2+bJx^2+bJy^2+bJz^2-dJ)*ee + gg + +% 2*(u1*(aJx-bJx) + u2*(aJy-bJy) + u3*(aJz-bJz)) + +% 2*(v1*(aJx+bJx) + v2*(aJy+bJy) + v3*(aJz+bJz)) + +% -2*( aJx*(R11*bJx+R12*bJy+R13*bJz) + +% aJy*(R21*bJx+R22*bJy+R23*bJz) + +% aJz*(R31*bJx+R32*bJy+R33*bJz) ) ; + + f1 = (a1x^2+a1y^2+a1z^2+b1x^2+b1y^2+b1z^2-d1)*ee + gg + + 2*(u1*(a1x-b1x) + u2*(a1y-b1y) + u3*(a1z-b1z)) + + 2*(v1*(a1x+b1x) + v2*(a1y+b1y) + v3*(a1z+b1z)) + + -2*( a1x*(R11*b1x+R12*b1y+R13*b1z) + + a1y*(R21*b1x+R22*b1y+R23*b1z) + + a1z*(R31*b1x+R32*b1y+R33*b1z) ) ; + + f2 = (a2x^2+a2y^2+a2z^2+b2x^2+b2y^2+b2z^2-d2)*ee + gg + + 2*(u1*(a2x-b2x) + u2*(a2y-b2y) + u3*(a2z-b2z)) + + 2*(v1*(a2x+b2x) + v2*(a2y+b2y) + v3*(a2z+b2z)) + + -2*( a2x*(R11*b2x+R12*b2y+R13*b2z) + + a2y*(R21*b2x+R22*b2y+R23*b2z) + + a2z*(R31*b2x+R32*b2y+R33*b2z) ) ; + + f3 = (a3x^2+a3y^2+a3z^2+b3x^2+b3y^2+b3z^2-d3)*ee + gg + + 2*(u1*(a3x-b3x) + u2*(a3y-b3y) + u3*(a3z-b3z)) + + 2*(v1*(a3x+b3x) + v2*(a3y+b3y) + v3*(a3z+b3z)) + + -2*( a3x*(R11*b3x+R12*b3y+R13*b3z) + + a3y*(R21*b3x+R22*b3y+R23*b3z) + + a3z*(R31*b3x+R32*b3y+R33*b3z) ) ; + + f4 = (a4x^2+a4y^2+a4z^2+b4x^2+b4y^2+b4z^2-d4)*ee + gg + + 2*(u1*(a4x-b4x) + u2*(a4y-b4y) + u3*(a4z-b4z)) + + 2*(v1*(a4x+b4x) + v2*(a4y+b4y) + v3*(a4z+b4z)) + + -2*( a4x*(R11*b4x+R12*b4y+R13*b4z) + + a4y*(R21*b4x+R22*b4y+R23*b4z) + + a4z*(R31*b4x+R32*b4y+R33*b4z) ) ; + + f5 = (a5x^2+a5y^2+a5z^2+b5x^2+b5y^2+b5z^2-d5)*ee + gg + + 2*(u1*(a5x-b5x) + u2*(a5y-b5y) + u3*(a5z-b5z)) + + 2*(v1*(a5x+b5x) + v2*(a5y+b5y) + v3*(a5z+b5z)) + + -2*( a5x*(R11*b5x+R12*b5y+R13*b5z) + + a5y*(R21*b5x+R22*b5y+R23*b5z) + + a5z*(R31*b5x+R32*b5y+R33*b5z) ) ; + + f6 = (a6x^2+a6y^2+a6z^2+b6x^2+b6y^2+b6z^2-d6)*ee + gg + + 2*(u1*(a6x-b6x) + u2*(a6y-b6y) + u3*(a6z-b6z)) + + 2*(v1*(a6x+b6x) + v2*(a6y+b6y) + v3*(a6z+b6z)) + + -2*( a6x*(R11*b6x+R12*b6y+R13*b6z) + + a6y*(R21*b6x+R22*b6y+R23*b6z) + + a6z*(R31*b6x+R32*b6y+R33*b6z) ) ; + +END diff --git a/test/data/Bertini_examples/Chap6ParameterHomotopy/ninepoint_parameter.input b/test/data/Bertini_examples/Chap6ParameterHomotopy/ninepoint_parameter.input new file mode 100644 index 0000000..bd80d70 --- /dev/null +++ b/test/data/Bertini_examples/Chap6ParameterHomotopy/ninepoint_parameter.input @@ -0,0 +1,161 @@ +% Nine-point path synthesis problem for four-bar linkages. +% +% Variables in 2 groups +% For the ab initio run: +% with UseRegeneration:0;, this will use 645,120 paths +% with UseRegeneration:1;, the path count is reduced to 152,224 of +% which only 48,704 are used in the last (most expensive) stage +% +% For subsequent parameter homotopy runs: +% taking advantage of symmetries, all runs after the ab initio one +% can be done with only 1442 paths. +% +CONFIG + ParameterHomotopy:1; % change to 2 after ab initio run is done + UseRegeneration:1; + TrackTolBeforeEG:1e-8; + TrackTolDuringEG:1e-8; + SliceTolBeforeEG:1e-8; + SliceTolDuringEG:1e-8; + SecurityMaxNorm:1e7; + EndpointFiniteThreshold:1e7; + PathTruncationThreshold:1e7; + SampleFactor:0.1; +END; + +INPUT + function f1,f2,f3,f4,f5,f6,f7,f8; + % Vectors a1,b1, a2,b2 in isotropic coordinates + variable_group a1,A1, b1,B1; + variable_group a2,A2, b2,B2; + % (pk,PK), k=1,...,8, are the precision points in isotropic coords + parameter p1,P1, p2,P2, p3,P3, p4,P4, p5,P5, p6,P6, p7,P7, p8,P8; + + % These highest terms do not depend on the precision points: + n1 = A1*b1; + N1 = a1*B1; + n2 = A2*b2; + N2 = a2*B2; + % nN = |n N| = det[n1 N1; n2 N2] + nN = n1*N2 - n2*N1; + + % For each precision point we have an equation: + % f = |v u|*|v U| + |u U|^2, + % where + % v = [v1+n1+N1; v2+n2+N2], + % u = [w1-n1; w2-n2], U = [W1-N1; W2-N2]; + % Expand the expressions far enough so that the cancellation + % of the highest terms can be exposed. + % Repeat this template for k=1,...,8 + % v1k = pk*Pk - a1*Pk - A1*pk; + % v2k = pk*Pk - a2*Pk - A2*pk; + % w1k = b1*Pk; W1k = B1*pk; + % w2k = b2*Pk; W2k = B2*pk; + % These sums are the entries in v + % s1k = v1k + n1 + N1; + % s2k = v2k + n2 + N2; + % These are the lower-order terms (that do not cancel) + % vuLowk = s1k*w2k - s2k*w1k - v1k*n2 + v2k*n1; + % vULowk = s1k*W2k - s2k*W1k - v1k*N2 + v2k*N1; + % uULowk = w1k*W2k - w2k*W1k - w1k*N2 + w2k*N1 - n1*W2k + n2*W1k; + % Finally, form f, with degree 8 terms cancelled out. + % (highest terms are |n N|*|N n| + |n N|^2 = 0) + % fk = vuLowk*vULowk - vuLowk*nN + vULowk*nN + uULowk^2 + 2*uULowk*nN; + + % k=1 + v11 = p1*P1 - a1*P1 - A1*p1; + v21 = p1*P1 - a2*P1 - A2*p1; + w11 = b1*P1; W11 = B1*p1; + w21 = b2*P1; W21 = B2*p1; + s11 = v11 + n1 + N1; + s21 = v21 + n2 + N2; + vuLow1 = s11*w21 - s21*w11 - v11*n2 + v21*n1; + vULow1 = s11*W21 - s21*W11 - v11*N2 + v21*N1; + uULow1 = w11*W21 - w21*W11 - w11*N2 + w21*N1 - n1*W21 + n2*W11; + f1 = vuLow1*vULow1 - vuLow1*nN + vULow1*nN + uULow1^2 + 2*uULow1*nN; + + % k=2 + v12 = p2*P2 - a1*P2 - A1*p2; + v22 = p2*P2 - a2*P2 - A2*p2; + w12 = b1*P2; W12 = B1*p2; + w22 = b2*P2; W22 = B2*p2; + s12 = v12 + n1 + N1; + s22 = v22 + n2 + N2; + vuLow2 = s12*w22 - s22*w12 - v12*n2 + v22*n1; + vULow2 = s12*W22 - s22*W12 - v12*N2 + v22*N1; + uULow2 = w12*W22 - w22*W12 - w12*N2 + w22*N1 - n1*W22 + n2*W12; + f2 = vuLow2*vULow2 - vuLow2*nN + vULow2*nN + uULow2^2 + 2*uULow2*nN; + + % k=3 + v13 = p3*P3 - a1*P3 - A1*p3; + v23 = p3*P3 - a2*P3 - A2*p3; + w13 = b1*P3; W13 = B1*p3; + w23 = b2*P3; W23 = B2*p3; + s13 = v13 + n1 + N1; + s23 = v23 + n2 + N2; + vuLow3 = s13*w23 - s23*w13 - v13*n2 + v23*n1; + vULow3 = s13*W23 - s23*W13 - v13*N2 + v23*N1; + uULow3 = w13*W23 - w23*W13 - w13*N2 + w23*N1 - n1*W23 + n2*W13; + f3 = vuLow3*vULow3 - vuLow3*nN + vULow3*nN + uULow3^2 + 2*uULow3*nN; + + % k=4 + v14 = p4*P4 - a1*P4 - A1*p4; + v24 = p4*P4 - a2*P4 - A2*p4; + w14 = b1*P4; W14 = B1*p4; + w24 = b2*P4; W24 = B2*p4; + s14 = v14 + n1 + N1; + s24 = v24 + n2 + N2; + vuLow4 = s14*w24 - s24*w14 - v14*n2 + v24*n1; + vULow4 = s14*W24 - s24*W14 - v14*N2 + v24*N1; + uULow4 = w14*W24 - w24*W14 - w14*N2 + w24*N1 - n1*W24 + n2*W14; + f4 = vuLow4*vULow4 - vuLow4*nN + vULow4*nN + uULow4^2 + 2*uULow4*nN; + + % k=5 + v15 = p5*P5 - a1*P5 - A1*p5; + v25 = p5*P5 - a2*P5 - A2*p5; + w15 = b1*P5; W15 = B1*p5; + w25 = b2*P5; W25 = B2*p5; + s15 = v15 + n1 + N1; + s25 = v25 + n2 + N2; + vuLow5 = s15*w25 - s25*w15 - v15*n2 + v25*n1; + vULow5 = s15*W25 - s25*W15 - v15*N2 + v25*N1; + uULow5 = w15*W25 - w25*W15 - w15*N2 + w25*N1 - n1*W25 + n2*W15; + f5 = vuLow5*vULow5 - vuLow5*nN + vULow5*nN + uULow5^2 + 2*uULow5*nN; + + % k=6 + v16 = p6*P6 - a1*P6 - A1*p6; + v26 = p6*P6 - a2*P6 - A2*p6; + w16 = b1*P6; W16 = B1*p6; + w26 = b2*P6; W26 = B2*p6; + s16 = v16 + n1 + N1; + s26 = v26 + n2 + N2; + vuLow6 = s16*w26 - s26*w16 - v16*n2 + v26*n1; + vULow6 = s16*W26 - s26*W16 - v16*N2 + v26*N1; + uULow6 = w16*W26 - w26*W16 - w16*N2 + w26*N1 - n1*W26 + n2*W16; + f6 = vuLow6*vULow6 - vuLow6*nN + vULow6*nN + uULow6^2 + 2*uULow6*nN; + + % k=7 + v17 = p7*P7 - a1*P7 - A1*p7; + v27 = p7*P7 - a2*P7 - A2*p7; + w17 = b1*P7; W17 = B1*p7; + w27 = b2*P7; W27 = B2*p7; + s17 = v17 + n1 + N1; + s27 = v27 + n2 + N2; + vuLow7 = s17*w27 - s27*w17 - v17*n2 + v27*n1; + vULow7 = s17*W27 - s27*W17 - v17*N2 + v27*N1; + uULow7 = w17*W27 - w27*W17 - w17*N2 + w27*N1 - n1*W27 + n2*W17; + f7 = vuLow7*vULow7 - vuLow7*nN + vULow7*nN + uULow7^2 + 2*uULow7*nN; + + % k=8 + v18 = p8*P8 - a1*P8 - A1*p8; + v28 = p8*P8 - a2*P8 - A2*p8; + w18 = b1*P8; W18 = B1*p8; + w28 = b2*P8; W28 = B2*p8; + s18 = v18 + n1 + N1; + s28 = v28 + n2 + N2; + vuLow8 = s18*w28 - s28*w18 - v18*n2 + v28*n1; + vULow8 = s18*W28 - s28*W18 - v18*N2 + v28*N1; + uULow8 = w18*W28 - w28*W18 - w18*N2 + w28*N1 - n1*W28 + n2*W18; + f8 = vuLow8*vULow8 - vuLow8*nN + vULow8*nN + uULow8^2 + 2*uULow8*nN; + +END; diff --git a/test/data/Bertini_examples/Chap6ParameterHomotopy/sextic.input b/test/data/Bertini_examples/Chap6ParameterHomotopy/sextic.input new file mode 100644 index 0000000..6f5299d --- /dev/null +++ b/test/data/Bertini_examples/Chap6ParameterHomotopy/sextic.input @@ -0,0 +1,10 @@ +% sextic.input +CONFIG + ParameterHomotopy:1; % setting for ab initio run +END; +INPUT + function f; + variable_group x; + parameter a0,a1,a2,a3,a4,a5,a6; + f = a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*a6))))); +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/._.DS_Store b/test/data/Bertini_examples/Chap7AdvancedIsolated/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/CircleParabola_eval.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/CircleParabola_eval.input new file mode 100644 index 0000000..56060be --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/CircleParabola_eval.input @@ -0,0 +1,14 @@ +% CircleParabola_eval.input +CONFIG + TrackType:-3; % evaluate system and Jacobian + % use 64-bit precision + MPType:1; + Precision:64; +END; +INPUT + function circle,parabola; + variable_group x,y; + + circle = x^2 + (y-1)^2 - 1; + parabola = y - 2*x^2; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/CircleParabola_newton.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/CircleParabola_newton.input new file mode 100644 index 0000000..8d21618 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/CircleParabola_newton.input @@ -0,0 +1,15 @@ +% CircleParabola_newton.input +CONFIG + % Perform a Newton iteration & approximate the condition number + TrackType:-1; + % use 64-bit precision + MPType:1; + Precision:64; +END; +INPUT + function circle,parabola; + variable_group x,y; + + circle = x^2 + (y-1)^2 - 1; + parabola = y - 2*x^2; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/CondNumCalc.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/CondNumCalc.input new file mode 100644 index 0000000..88b43db --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/CondNumCalc.input @@ -0,0 +1,17 @@ +% CondNumCalc.input +CONFIG + % Perform a Newton iteration & approximate the condition number + TrackType:-1; + % Utilize 256-bit fixed precision + MPType:1; + Precision:256; + % fix a seed for the random number generator + RandomSeed:1934835; +END; +INPUT + function circle,parabola; + variable_group x,y; + + circle = x^2 + (y-1)^2 - 1; + parabola = y - 2*x^2; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/CondNumCalc.start b/test/data/Bertini_examples/Chap7AdvancedIsolated/CondNumCalc.start new file mode 100644 index 0000000..8500b86 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/CondNumCalc.start @@ -0,0 +1,14 @@ +4 + +-8.660254037844386e-01 9.492190020110591e-17 +1.500000000000000e+00 6.120321263680673e-17 + +8.660254037844388e-01 -2.186564731360141e-16 +1.500000000000000e+00 -1.412715430748612e-16 + +-2.213743081408535e-13 -1.498562286411079e-13 +2.540827022107365e-15 -1.330798662382149e-15 + +2.878540067625655e-13 1.392857465195220e-13 +3.125787117584775e-15 -1.703491954589669e-15 +% CondNumCalc.start diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/FixedPoint.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/FixedPoint.input new file mode 100644 index 0000000..67bd114 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/FixedPoint.input @@ -0,0 +1,15 @@ +% FixedPoint.input +CONFIG + % Use a fixed-point homotopy to sharpen + ParameterHomotopy:2; + FinalTol:1e-20; +END; +INPUT + function parabola,twolines + variable_group x,y; + parameter t,x0,y0; + random gamma; + + parabola = (1-t)*(y - x^2) + gamma*t*(x - x0); + twolines = (1-t)*(x^2 - y^2) + gamma*t*(y - y0); +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/FunctionEval.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/FunctionEval.input new file mode 100644 index 0000000..2c9be70 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/FunctionEval.input @@ -0,0 +1,17 @@ +% FunctionEval.input +CONFIG + % Evaluate a user-defined homotopy using 64-bit precision + UserHomotopy:1; + TrackType:-4; + MPType:1; + Precision:64; +END; +INPUT + function f; + variable x; + pathvariable T; + parameter t; + t = T; + + f = exp(sin(x/(1+x))) + 1/cos(x-2) - 1; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/FunctionEval.start b/test/data/Bertini_examples/Chap7AdvancedIsolated/FunctionEval.start new file mode 100644 index 0000000..0144348 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/FunctionEval.start @@ -0,0 +1,4 @@ +1 + +-0.5 0 +% FunctionEval.start diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/HighCondNum.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/HighCondNum.input new file mode 100644 index 0000000..ec4ffba --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/HighCondNum.input @@ -0,0 +1,7 @@ +% HighCondNum.input + function f,g; + variable_group x,y; + + f = y - x^10; + g = y - 1e-10; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/HighCondNum_sharpen.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/HighCondNum_sharpen.input new file mode 100644 index 0000000..2f0b4d2 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/HighCondNum_sharpen.input @@ -0,0 +1,12 @@ +% HighCondNum_sharpen.input +CONFIG + SharpenOnly:1; % use the sharpening module + CondNumThreshold:1e12; % adjust the condition number threshold +END; +INPUT + function f,g; + variable_group x,y; + + f = y - x^10; + g = y - 1e-10; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/HyperbolaParabola.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/HyperbolaParabola.input new file mode 100644 index 0000000..4ab7b47 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/HyperbolaParabola.input @@ -0,0 +1,7 @@ +%HyperbolaParabola.input + function hyperbola,parabola; + variable_group x,y; + + hyperbola = x^2 - y^2 - 1; + parabola = x - y^2 - 1; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/HyperbolaParabola_sharpen.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/HyperbolaParabola_sharpen.input new file mode 100644 index 0000000..dc5bf24 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/HyperbolaParabola_sharpen.input @@ -0,0 +1,12 @@ +% HyperbolaParabola_sharpen.input +CONFIG + SharpenOnly:1; % use the sharpening module + SharpenDigits:20; % sharpen to 20 digits +END; +INPUT + function hyperbola,parabola; + variable_group x,y; + + hyperbola = x^2 - y^2 - 1; + parabola = x - y^2 - 1; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/NewtonHomotopy.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/NewtonHomotopy.input new file mode 100644 index 0000000..2abae6d --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/NewtonHomotopy.input @@ -0,0 +1,15 @@ +% NewtonHomotopy.input +CONFIG + % Use a Newton homotopy to sharpen + ParameterHomotopy:2; + FinalTol:1e-20; +END; +INPUT + function parabola,twolines + variable_group x,y; + parameter t,x0,y0; + random gamma; + + parabola = (1-t+gamma*t)*(y - x^2) - gamma*t*(y0 - x0^2); + twolines = (1-t+gamma*t)*(x^2 - y^2) - gamma*t*(x0^2 - y0^2); +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/RoundingError.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/RoundingError.input new file mode 100644 index 0000000..1f22cbf --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/RoundingError.input @@ -0,0 +1,12 @@ +% RoundingError.input + function f1,f2; + variable_group x; + variable_group y; + constant a,b; + + a = 1.414214; % round sqrt(2) to 6 decimal places + b = 2; + + f1 = x*y^3 - a*y^3 - 1; + f2 = x^2 - b; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/ScaledSystem.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/ScaledSystem.input new file mode 100644 index 0000000..e03ad8a --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/ScaledSystem.input @@ -0,0 +1,11 @@ +% ScaledSystem.input +CONFIG + SharpenDigits:30; % sharpen endpoints to 30 digits +END; +INPUT + function f1,f2; + variable_group hatx,haty; + + f1 = hatx*haty - 1; + f2 = hatx - haty - 10; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/SharpenDigits.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/SharpenDigits.input new file mode 100644 index 0000000..d095e07 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/SharpenDigits.input @@ -0,0 +1,12 @@ +% SharpenDigits.input +CONFIG + % Solve using a total-degree homotopy + SharpenDigits:20; % sharpen the endpoints to 20 digits +END; +INPUT + function circle,parabola; + variable_group x,y; + + circle = x^2 + (y-1)^2 - 1; + parabola = y - 2*x^2; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/Unscale.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/Unscale.input new file mode 100644 index 0000000..c3c68c3 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/Unscale.input @@ -0,0 +1,14 @@ +% Unscale.input +CONFIG + TrackType:-4; % perform evaluation + % Utilize 96-bit fixed precision + MPType:1; + Precision:96; +END; +INPUT + function x,y; + variable_group hatx,haty; + + x = 1e-11*hatx; + y = 1e-5*haty; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_NewtonHomotopy.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_NewtonHomotopy.input new file mode 100644 index 0000000..ec7e33f --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_NewtonHomotopy.input @@ -0,0 +1,14 @@ +% UserDefined_NewtonHomotopy.input +CONFIG + % Track a user-defined homotopy + UserHomotopy:1; +END; +INPUT + function f; + variable x; + pathvariable T; + parameter t; + t = T; + + f = exp(sin(x/(1+x))) + 1/cos(x-2) - 1 - t*(-1.81713970082); +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_ProductSpace.input b/test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_ProductSpace.input new file mode 100644 index 0000000..242b7f5 --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_ProductSpace.input @@ -0,0 +1,19 @@ +% UserDefined_ProductSpace.input +CONFIG + % Track a user-defined homotopy on a product space + UserHomotopy:2; + SecurityLevel:1; +END; +INPUT + function f,g; + variable_group x; + variable_group y; + pathvariable T; + t = 1-T; % t goes from 0 to 1 + parameter a,b; + a = sin(t*Pi/2); + b = t; + + f = x^2 - 3*a*x - 4; + g = x*y + y - b; +END; diff --git a/test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_ProductSpace.start b/test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_ProductSpace.start new file mode 100644 index 0000000..becc88a --- /dev/null +++ b/test/data/Bertini_examples/Chap7AdvancedIsolated/UserDefined_ProductSpace.start @@ -0,0 +1,8 @@ +2 + +2 0 +0 0 + +-2 0 +0 0 +% UserDefined_ProductSpace.start diff --git a/test/data/Bertini_examples/Chap8PositiveDimensional/._.DS_Store b/test/data/Bertini_examples/Chap8PositiveDimensional/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap8PositiveDimensional/BricardSixR.input b/test/data/Bertini_examples/Chap8PositiveDimensional/BricardSixR.input new file mode 100644 index 0000000..27c442e --- /dev/null +++ b/test/data/Bertini_examples/Chap8PositiveDimensional/BricardSixR.input @@ -0,0 +1,80 @@ +% Bricard 6R (six-revolute) mechanism +% +% This is a special case of 6R serial-link inverse kinematics. +% This closed-loop 6R mechanism has a 1-degree-of-freedom motion, +% so we use TrackType:1 to find that curve. +% +CONFIG + TrackType:1; +END; + +INPUT + % link lengths + constant a1,a2,a3,a4,a5; + % link offsets + constant d2,d3,d4,d5; + % twist cosines + constant c1,c2,c3,c4,c5; + % endpoint position + constant px,py,pz; + % joint 1 orientation (fixed) + constant z1x,z1y,z1z; + % joint 6 orientation (fixed) + constant z6x,z6y,z6z; + + % give values to constants + z1x=1; z1y=0; z1z=0; + z6x=0; z6y=0; z6z=1; + a1=1; a2=1; a3=1; a4=1; a5=1; + d2=0; d3=0; d4=0; d5=0; + c1=0; c2=0; c3=0; c4=0; c5=0; + px=0; py=1; pz=0; + + variable_group z2x,z2y,z2z, z3x,z3y,z3z, z4x,z4y,z4z, z5x,z5y,z5z; + + function unit2, unit3, unit4, unit5; + function twist1, twist2, twist3, twist4, twist5; + function X,Y,Z; + + unit2 = z2x^2 + z2y^2 + z2z^2 -1; + unit3 = z3x^2 + z3y^2 + z3z^2 -1; + unit4 = z4x^2 + z4y^2 + z4z^2 -1; + unit5 = z5x^2 + z5y^2 + z5z^2 -1; + twist1 = z1x*z2x + z1y*z2y + z1z*z2z - c1; + twist2 = z2x*z3x + z2y*z3y + z2z*z3z - c2; + twist3 = z3x*z4x + z3y*z4y + z3z*z4z - c3; + twist4 = z4x*z5x + z4y*z5y + z4z*z5z - c4; + twist5 = z5x*z6x + z5y*z6y + z5z*z6z - c5; + % form cross products + x1x = z1y*z2z - z1z*z2y; + x2x = z2y*z3z - z2z*z3y; + x3x = z3y*z4z - z3z*z4y; + x4x = z4y*z5z - z4z*z5y; + x5x = z5y*z6z - z5z*z6y; + x1y = z1z*z2x - z1x*z2z; + x2y = z2z*z3x - z2x*z3z; + x3y = z3z*z4x - z3x*z4z; + x4y = z4z*z5x - z4x*z5z; + x5y = z5z*z6x - z5x*z6z; + x1z = z1x*z2y - z1y*z2x; + x2z = z2x*z3y - z2y*z3x; + x3z = z3x*z4y - z3y*z4x; + x4z = z4x*z5y - z4y*z5x; + x5z = z5x*z6y - z5y*z6x; + % position + X = a1*x1x + d2*z2x + + a2*x2x + d3*z3x + + a3*x3x + d4*z4x + + a4*x4x + d5*z5x + + a5*x5x - px; + Y = a1*x1y + d2*z2y + + a2*x2y + d3*z3y + + a3*x3y + d4*z4y + + a4*x4y + d5*z5y + + a5*x5y - py; + Z = a1*x1z + d2*z2z + + a2*x2z + d3*z3z + + a3*x3z + d4*z4z + + a4*x4z + d5*z5z + + a5*x5z - pz; +END; diff --git a/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffy.input b/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffy.input new file mode 100644 index 0000000..409d018 --- /dev/null +++ b/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffy.input @@ -0,0 +1,152 @@ +% Bertini file for Griffis-Duffy platform forward kinematics +% +% This is the general Griffis-Duffy, special case of Stewart-Gough +% +% We modify the general Stewart-Gough system to put the parameters +% on the Griffis-Duffy parameter space. +CONFIG + TrackType:1; +END + +INPUT + % Base & moving platforms are both triangles with joints + % at vertices and one joint along each edge. + % Specify this by giving random vertices and then + % interpolating to put random point on each edge. + % As the figures are planar, we set z-coordinates to zero. + % Vertices for the stationary rigid body + random a1x,a1y, a3x,a3y, a5x,a5y; + constant a1z,a2z,a3z,a4z,a5z,a6z; + a1z=0;a2z=0;a3z=0;a4z=0;a5z=0;a6z=0; + % Interpolating constants for sides + random a2,a4,a6; + a2x = a2*a1x + (1-a2)*a3x; + a2y = a2*a1y + (1-a2)*a3y; + a4x = a4*a3x + (1-a4)*a5x; + a4y = a4*a3y + (1-a4)*a5y; + a6x = a6*a5x + (1-a6)*a1x; + a6y = a6*a5y + (1-a6)*a1y; + % Do similar for the moving rigid body + % Vertices for the stationary rigid body + random b2x,b2y, b4x,b4y, b6x,b6y; + constant b1z,b2z,b3z,b4z,b5z,b6z; + b1z=0;b2z=0;b3z=0;b4z=0;b5z=0;b6z=0; + % Interpolating constants for sides + random b1,b3,b5; + b1x = b1*b6x + (1-b1)*b2x; + b1y = b1*b6y + (1-b1)*b2y; + b3x = b3*b2x + (1-b3)*b4x; + b3y = b3*b2y + (1-b3)*b4y; + b5x = b5*b4x + (1-b5)*b6x; + b5y = b5*b4y + (1-b5)*b6y; + % squared distances between point pairs + random d1,d2,d3,d4,d5,d6; + % + + % These will be the squared distance functions + function f1,f2,f3,f4,f5,f6; + % The Study quadric + function Study; + + % Use Study coordinates for the position & orientation of the moving body. + hom_variable_group e0,e1,e2,e3,g0,g1,g2,g3; + + % Let X be the 4x4 representation of quaternion (x0,x1,x2,x3) + % So + % X = [ x0 -x1 -x2 -x3 + % x1 x0 -x3 x2 + % x2 x3 x0 -x1 + % x3 -x2 x1 x0 ] + % Treat vector (v1,v2,v3) as quaternion (0,v1,v2,v3). + % We also say that Re(x) = x0 or equivalently, Re(X) = x0*I. + + % Quaternions obey the relation X*X' = |(x0,x1,x2,x3)|^2 = |X|^2 + % Let ee = E*E', gg = G*G': + ee = e0^2 + e1^2 + e2^2 +e3^2; + gg = g0^2 + g1^2 + g2^2 +g3^2; + + % After transformation, a point b = (b1,b2,b3) becomes + % Transf(b) = (E*B*E' + G*E')/ee + % with the Study quadric side condition of + % Study = Re(G*E') = 0 + Study = g0*e0 + g1*e1 + g2*e2 + g3*e3; + + % Accordingly, the governing equations are the squared distance relations + % (*) d = | (E*B*E' + G*E')/ee - A |^2 + % = [ (E*B*E' + G*E')/ee - A ]*[ (E*B'*E' + E*G')/ee - A'] + % After expanding this, several instances of E*E' = ee*I appear. After + % simplifying ee/ee = 1 (cases of ee=0 are meaningless) and then + % clearing the denominator by multiplying by ee, (*) becomes + % a quadric relation in E,G, with A,B,d considered constants. + % We apply this 6 times for d_i, a_i, b_i. + + % We simplify (*) with some vector algebra, where the following + % terms appear: + R11 = e0^2+e1^2-e2^2-e3^2; + R12 = 2*(-e0*e3+e1*e2); + R13 = 2*( e0*e2+e1*e3); + R21 = 2*( e0*e3+e2*e1); + R22 = e0^2-e1^2+e2^2-e3^2; + R23 = 2*(-e0*e1+e2*e3); + R31 = 2*(-e0*e2+e3*e1); + R32 = 2*( e0*e1+e3*e2); + R33 = e0^2-e1^2-e2^2+e3^2; + u1 = g0*e1 - e0*g1; + u2 = g0*e2 - e0*g2; + u3 = g0*e3 - e0*g3; + v1 = g2*e3 - g3*e2; + v2 = g3*e1 - g1*e3; + v3 = g1*e2 - g2*e1; + + % Now, we form the 6 distance equations. + % Write it in terms of J, then substitute J = 1,...,6 +% fJ = (aJx^2+aJy^2+aJz^2+bJx^2+bJy^2+bJz^2-dJ)*ee + gg + +% 2*(u1*(aJx-bJx) + u2*(aJy-bJy) + u3*(aJz-bJz)) + +% 2*(v1*(aJx+bJx) + v2*(aJy+bJy) + v3*(aJz+bJz)) + +% -2*( aJx*(R11*bJx+R12*bJy+R13*bJz) + +% aJy*(R21*bJx+R22*bJy+R23*bJz) + +% aJz*(R31*bJx+R32*bJy+R33*bJz) ) ; + + f1 = (a1x^2+a1y^2+a1z^2+b1x^2+b1y^2+b1z^2-d1)*ee + gg + + 2*(u1*(a1x-b1x) + u2*(a1y-b1y) + u3*(a1z-b1z)) + + 2*(v1*(a1x+b1x) + v2*(a1y+b1y) + v3*(a1z+b1z)) + + -2*( a1x*(R11*b1x+R12*b1y+R13*b1z) + + a1y*(R21*b1x+R22*b1y+R23*b1z) + + a1z*(R31*b1x+R32*b1y+R33*b1z) ) ; + + f2 = (a2x^2+a2y^2+a2z^2+b2x^2+b2y^2+b2z^2-d2)*ee + gg + + 2*(u1*(a2x-b2x) + u2*(a2y-b2y) + u3*(a2z-b2z)) + + 2*(v1*(a2x+b2x) + v2*(a2y+b2y) + v3*(a2z+b2z)) + + -2*( a2x*(R11*b2x+R12*b2y+R13*b2z) + + a2y*(R21*b2x+R22*b2y+R23*b2z) + + a2z*(R31*b2x+R32*b2y+R33*b2z) ) ; + + f3 = (a3x^2+a3y^2+a3z^2+b3x^2+b3y^2+b3z^2-d3)*ee + gg + + 2*(u1*(a3x-b3x) + u2*(a3y-b3y) + u3*(a3z-b3z)) + + 2*(v1*(a3x+b3x) + v2*(a3y+b3y) + v3*(a3z+b3z)) + + -2*( a3x*(R11*b3x+R12*b3y+R13*b3z) + + a3y*(R21*b3x+R22*b3y+R23*b3z) + + a3z*(R31*b3x+R32*b3y+R33*b3z) ) ; + + f4 = (a4x^2+a4y^2+a4z^2+b4x^2+b4y^2+b4z^2-d4)*ee + gg + + 2*(u1*(a4x-b4x) + u2*(a4y-b4y) + u3*(a4z-b4z)) + + 2*(v1*(a4x+b4x) + v2*(a4y+b4y) + v3*(a4z+b4z)) + + -2*( a4x*(R11*b4x+R12*b4y+R13*b4z) + + a4y*(R21*b4x+R22*b4y+R23*b4z) + + a4z*(R31*b4x+R32*b4y+R33*b4z) ) ; + + f5 = (a5x^2+a5y^2+a5z^2+b5x^2+b5y^2+b5z^2-d5)*ee + gg + + 2*(u1*(a5x-b5x) + u2*(a5y-b5y) + u3*(a5z-b5z)) + + 2*(v1*(a5x+b5x) + v2*(a5y+b5y) + v3*(a5z+b5z)) + + -2*( a5x*(R11*b5x+R12*b5y+R13*b5z) + + a5y*(R21*b5x+R22*b5y+R23*b5z) + + a5z*(R31*b5x+R32*b5y+R33*b5z) ) ; + + f6 = (a6x^2+a6y^2+a6z^2+b6x^2+b6y^2+b6z^2-d6)*ee + gg + + 2*(u1*(a6x-b6x) + u2*(a6y-b6y) + u3*(a6z-b6z)) + + 2*(v1*(a6x+b6x) + v2*(a6y+b6y) + v3*(a6z+b6z)) + + -2*( a6x*(R11*b6x+R12*b6y+R13*b6z) + + a6y*(R21*b6x+R22*b6y+R23*b6z) + + a6z*(R31*b6x+R32*b6y+R33*b6z) ) ; + +END diff --git a/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyFoldable.input b/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyFoldable.input new file mode 100644 index 0000000..eb3d1e7 --- /dev/null +++ b/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyFoldable.input @@ -0,0 +1,167 @@ +% Bertini file for Foldable Griffis-Duffy Type platform forward kinematics +% +% This special case of Stewart-Gough is Griffis-Duffy with +% base & moving triangles as equilateral and congruent, with joints at +% vertices and midpoints. Leg lengths all equal to altitude of +% triangles +% +% We modify the general Stewart-Gough system to put the parameters +% on the Griffis-Duffy parameter space. +CONFIG + TrackType:1; +END + +INPUT + % Base & moving platforms are both triangles with joints + % at vertices and one joint along each edge. + % Specify this by giving random vertices and then + % interpolating to put random point on each edge. + % As the figures are planar, we set z-coordinates to zero. + constant sqrt3; + sqrt3 = 3^(1/2); + % Vertices for the stationary rigid body + constant a1x,a1y, a3x,a3y, a5x,a5y; + a1x = -sqrt3; a1y = -1; + a3x = sqrt3; a3y = -1; + a5x = 0; a5y = 2; + constant a1z,a2z,a3z,a4z,a5z,a6z; + a1z=0;a2z=0;a3z=0;a4z=0;a5z=0;a6z=0; + % Interpolating constants for sides + constant a2,a4,a6; + a2=0.5;a4=0.5;a6=0.5; + a2x = a2*a1x + (1-a2)*a3x; + a2y = a2*a1y + (1-a2)*a3y; + a4x = a4*a3x + (1-a4)*a5x; + a4y = a4*a3y + (1-a4)*a5y; + a6x = a6*a5x + (1-a6)*a1x; + a6y = a6*a5y + (1-a6)*a1y; + % Do similar for the moving rigid body + % Vertices for the stationary rigid body + constant b2x,b2y, b4x,b4y, b6x,b6y; + b2x = 0; b2y=2; + b4x = -sqrt3; b4y = -1; + b6x = sqrt3; b6y = -1; + constant b1z,b2z,b3z,b4z,b5z,b6z; + b1z=0;b2z=0;b3z=0;b4z=0;b5z=0;b6z=0; + % Interpolating constants for sides + constant b1,b3,b5; + b1=0.5;b3=0.5;b5=0.5; + b1x = b1*b6x + (1-b1)*b2x; + b1y = b1*b6y + (1-b1)*b2y; + b3x = b3*b2x + (1-b3)*b4x; + b3y = b3*b2y + (1-b3)*b4y; + b5x = b5*b4x + (1-b5)*b6x; + b5y = b5*b4y + (1-b5)*b6y; + % squared distances between point pairs + constant d1; + d1=9; + d2=d1;d3=d1;d4=d1;d5=d1;d6=d1; + % + + % These will be the squared distance functions + function f1,f2,f3,f4,f5,f6; + % The Study quadric + function Study; + + % Use Study coordinates for the position & orientation of the moving body. + hom_variable_group e0,e1,e2,e3,g0,g1,g2,g3; + + % Let X be the 4x4 representation of quaternion (x0,x1,x2,x3) + % So + % X = [ x0 -x1 -x2 -x3 + % x1 x0 -x3 x2 + % x2 x3 x0 -x1 + % x3 -x2 x1 x0 ] + % Treat vector (v1,v2,v3) as quaternion (0,v1,v2,v3). + % We also say that Re(x) = x0 or equivalently, Re(X) = x0*I. + + % Quaternions obey the relation X*X' = |(x0,x1,x2,x3)|^2 = |X|^2 + % Let ee = E*E', gg = G*G': + ee = e0^2 + e1^2 + e2^2 +e3^2; + gg = g0^2 + g1^2 + g2^2 +g3^2; + + % After transformation, a point b = (b1,b2,b3) becomes + % Transf(b) = (E*B*E' + G*E')/ee + % with the Study quadric side condition of + % Study = Re(G*E') = 0 + Study = g0*e0 + g1*e1 + g2*e2 + g3*e3; + + % Accordingly, the governing equations are the squared distance relations + % (*) d = | (E*B*E' + G*E')/ee - A |^2 + % = [ (E*B*E' + G*E')/ee - A ]*[ (E*B'*E' + E*G')/ee - A'] + % After expanding this, several instances of E*E' = ee*I appear. After + % simplifying ee/ee = 1 (cases of ee=0 are meaningless) and then + % clearing the denominator by multiplying by ee, (*) becomes + % a quadric relation in E,G, with A,B,d considered constants. + % We apply this 6 times for d_i, a_i, b_i. + + % We simplify (*) with some vector algebra, where the following + % terms appear: + R11 = e0^2+e1^2-e2^2-e3^2; + R12 = 2*(-e0*e3+e1*e2); + R13 = 2*( e0*e2+e1*e3); + R21 = 2*( e0*e3+e2*e1); + R22 = e0^2-e1^2+e2^2-e3^2; + R23 = 2*(-e0*e1+e2*e3); + R31 = 2*(-e0*e2+e3*e1); + R32 = 2*( e0*e1+e3*e2); + R33 = e0^2-e1^2-e2^2+e3^2; + u1 = g0*e1 - e0*g1; + u2 = g0*e2 - e0*g2; + u3 = g0*e3 - e0*g3; + v1 = g2*e3 - g3*e2; + v2 = g3*e1 - g1*e3; + v3 = g1*e2 - g2*e1; + + % Now, we form the 6 distance equations. + % Write it in terms of J, then substitute J = 1,...,6 +% fJ = (aJx^2+aJy^2+aJz^2+bJx^2+bJy^2+bJz^2-dJ)*ee + gg + +% 2*(u1*(aJx-bJx) + u2*(aJy-bJy) + u3*(aJz-bJz)) + +% 2*(v1*(aJx+bJx) + v2*(aJy+bJy) + v3*(aJz+bJz)) + +% -2*( aJx*(R11*bJx+R12*bJy+R13*bJz) + +% aJy*(R21*bJx+R22*bJy+R23*bJz) + +% aJz*(R31*bJx+R32*bJy+R33*bJz) ) ; + + f1 = (a1x^2+a1y^2+a1z^2+b1x^2+b1y^2+b1z^2-d1)*ee + gg + + 2*(u1*(a1x-b1x) + u2*(a1y-b1y) + u3*(a1z-b1z)) + + 2*(v1*(a1x+b1x) + v2*(a1y+b1y) + v3*(a1z+b1z)) + + -2*( a1x*(R11*b1x+R12*b1y+R13*b1z) + + a1y*(R21*b1x+R22*b1y+R23*b1z) + + a1z*(R31*b1x+R32*b1y+R33*b1z) ) ; + + f2 = (a2x^2+a2y^2+a2z^2+b2x^2+b2y^2+b2z^2-d2)*ee + gg + + 2*(u1*(a2x-b2x) + u2*(a2y-b2y) + u3*(a2z-b2z)) + + 2*(v1*(a2x+b2x) + v2*(a2y+b2y) + v3*(a2z+b2z)) + + -2*( a2x*(R11*b2x+R12*b2y+R13*b2z) + + a2y*(R21*b2x+R22*b2y+R23*b2z) + + a2z*(R31*b2x+R32*b2y+R33*b2z) ) ; + + f3 = (a3x^2+a3y^2+a3z^2+b3x^2+b3y^2+b3z^2-d3)*ee + gg + + 2*(u1*(a3x-b3x) + u2*(a3y-b3y) + u3*(a3z-b3z)) + + 2*(v1*(a3x+b3x) + v2*(a3y+b3y) + v3*(a3z+b3z)) + + -2*( a3x*(R11*b3x+R12*b3y+R13*b3z) + + a3y*(R21*b3x+R22*b3y+R23*b3z) + + a3z*(R31*b3x+R32*b3y+R33*b3z) ) ; + + f4 = (a4x^2+a4y^2+a4z^2+b4x^2+b4y^2+b4z^2-d4)*ee + gg + + 2*(u1*(a4x-b4x) + u2*(a4y-b4y) + u3*(a4z-b4z)) + + 2*(v1*(a4x+b4x) + v2*(a4y+b4y) + v3*(a4z+b4z)) + + -2*( a4x*(R11*b4x+R12*b4y+R13*b4z) + + a4y*(R21*b4x+R22*b4y+R23*b4z) + + a4z*(R31*b4x+R32*b4y+R33*b4z) ) ; + + f5 = (a5x^2+a5y^2+a5z^2+b5x^2+b5y^2+b5z^2-d5)*ee + gg + + 2*(u1*(a5x-b5x) + u2*(a5y-b5y) + u3*(a5z-b5z)) + + 2*(v1*(a5x+b5x) + v2*(a5y+b5y) + v3*(a5z+b5z)) + + -2*( a5x*(R11*b5x+R12*b5y+R13*b5z) + + a5y*(R21*b5x+R22*b5y+R23*b5z) + + a5z*(R31*b5x+R32*b5y+R33*b5z) ) ; + + f6 = (a6x^2+a6y^2+a6z^2+b6x^2+b6y^2+b6z^2-d6)*ee + gg + + 2*(u1*(a6x-b6x) + u2*(a6y-b6y) + u3*(a6z-b6z)) + + 2*(v1*(a6x+b6x) + v2*(a6y+b6y) + v3*(a6z+b6z)) + + -2*( a6x*(R11*b6x+R12*b6y+R13*b6z) + + a6y*(R21*b6x+R22*b6y+R23*b6z) + + a6z*(R31*b6x+R32*b6y+R33*b6z) ) ; + +END diff --git a/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyI.input b/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyI.input new file mode 100644 index 0000000..548544e --- /dev/null +++ b/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyI.input @@ -0,0 +1,173 @@ +% Bertini file for Griffis-Duffy Type I platform forward kinematics +% +% This special case of Stewart-Gough is Griffis-Duffy with +% base & moving triangles as equilateral, with joints at +% vertices and midpoints. Leg lengths compatible. +% +% We modify the general Stewart-Gough system to put the parameters +% on the Griffis-Duffy parameter space. +CONFIG + TrackType:1; +END + +INPUT + % Base & moving platforms are both triangles with joints + % at vertices and one joint along each edge. + % Specify this by giving random vertices and then + % interpolating to put random point on each edge. + % As the figures are planar, we set z-coordinates to zero. + constant sqrt3; + sqrt3 = 3^(1/2); + % Vertices for the stationary rigid body + constant a1x,a1y, a3x,a3y, a5x,a5y; + a1x = -sqrt3; a1y = -1; + a3x = sqrt3; a3y = -1; + a5x = 0; a5y = 2; + constant a1z,a2z,a3z,a4z,a5z,a6z; + a1z=0;a2z=0;a3z=0;a4z=0;a5z=0;a6z=0; + % Interpolating constants for sides + constant a2,a4,a6; + a2=0.5;a4=0.5;a6=0.5; + a2x = a2*a1x + (1-a2)*a3x; + a2y = a2*a1y + (1-a2)*a3y; + a4x = a4*a3x + (1-a4)*a5x; + a4y = a4*a3y + (1-a4)*a5y; + a6x = a6*a5x + (1-a6)*a1x; + a6y = a6*a5y + (1-a6)*a1y; + % Do similar for the moving rigid body + % Vertices for the stationary rigid body, scaling factor rho. + constant rho; + rho = 0.40848840084869084689607210007511811758273381523777e0 +I*0.43843518180137204471464687496504664346923820863761e0; + constant b2x,b2y, b4x,b4y, b6x,b6y; + b2x = 0; b2y=rho*2; + b4x = -rho*sqrt3; b4y = -rho; + b6x = rho*sqrt3; b6y = -rho; + constant b1z,b2z,b3z,b4z,b5z,b6z; + b1z=0;b2z=0;b3z=0;b4z=0;b5z=0;b6z=0; + % Interpolating constants for sides + constant b1,b3,b5; + b1=0.5;b3=0.5;b5=0.5; + b1x = b1*b6x + (1-b1)*b2x; + b1y = b1*b6y + (1-b1)*b2y; + b3x = b3*b2x + (1-b3)*b4x; + b3y = b3*b2y + (1-b3)*b4y; + b5x = b5*b4x + (1-b5)*b6x; + b5y = b5*b4y + (1-b5)*b6y; + % squared distances between point pairs + constant d1,d2,d3,d4,d5,d6; + d1= 0.60253285154416311666763946757947656005254767936440e1 +I*0.46244460773969870774591688042239016441342159529488e1; + d2= 0.68195377486446525775410545489180535494469537475256e0 +I*0.22337719013829322825025502032123983328376923876513e1; + d3= 0.33100335856880728115480859653452549775233437122361e1 +I*-0.17966811115594162795869439796591218630615640979776e1; + d4= 0.15579139233250532088351660739114320197236432225561e1 +I*0.29335247385730361447386332238267248559416170233522e1; + d5= 0.40898037844000270035640955828371496115912598858697e1 +I*0.22349953092285726839281624652249023930268956704736e1; + d6= 0.19570344722206797029694886155922008947671975753046e1 +I*0.31191859883274302363997819325785667988053249319080e1; + + % + + % These will be the squared distance functions + function f1,f2,f3,f4,f5,f6; + % The Study quadric + function Study; + + % Use Study coordinates for the position & orientation of the moving body. + hom_variable_group e0,e1,e2,e3,g0,g1,g2,g3; + + % Let X be the 4x4 representation of quaternion (x0,x1,x2,x3) + % So + % X = [ x0 -x1 -x2 -x3 + % x1 x0 -x3 x2 + % x2 x3 x0 -x1 + % x3 -x2 x1 x0 ] + % Treat vector (v1,v2,v3) as quaternion (0,v1,v2,v3). + % We also say that Re(x) = x0 or equivalently, Re(X) = x0*I. + + % Quaternions obey the relation X*X' = |(x0,x1,x2,x3)|^2 = |X|^2 + % Let ee = E*E', gg = G*G': + ee = e0^2 + e1^2 + e2^2 +e3^2; + gg = g0^2 + g1^2 + g2^2 +g3^2; + + % After transformation, a point b = (b1,b2,b3) becomes + % Transf(b) = (E*B*E' + G*E')/ee + % with the Study quadric side condition of + % Study = Re(G*E') = 0 + Study = g0*e0 + g1*e1 + g2*e2 + g3*e3; + + % Accordingly, the governing equations are the squared distance relations + % (*) d = | (E*B*E' + G*E')/ee - A |^2 + % = [ (E*B*E' + G*E')/ee - A ]*[ (E*B'*E' + E*G')/ee - A'] + % After expanding this, several instances of E*E' = ee*I appear. After + % simplifying ee/ee = 1 (cases of ee=0 are meaningless) and then + % clearing the denominator by multiplying by ee, (*) becomes + % a quadric relation in E,G, with A,B,d considered constants. + % We apply this 6 times for d_i, a_i, b_i. + + % We simplify (*) with some vector algebra, where the following + % terms appear: + R11 = e0^2+e1^2-e2^2-e3^2; + R12 = 2*(-e0*e3+e1*e2); + R13 = 2*( e0*e2+e1*e3); + R21 = 2*( e0*e3+e2*e1); + R22 = e0^2-e1^2+e2^2-e3^2; + R23 = 2*(-e0*e1+e2*e3); + R31 = 2*(-e0*e2+e3*e1); + R32 = 2*( e0*e1+e3*e2); + R33 = e0^2-e1^2-e2^2+e3^2; + u1 = g0*e1 - e0*g1; + u2 = g0*e2 - e0*g2; + u3 = g0*e3 - e0*g3; + v1 = g2*e3 - g3*e2; + v2 = g3*e1 - g1*e3; + v3 = g1*e2 - g2*e1; + + % Now, we form the 6 distance equations. + % Write it in terms of J, then substitute J = 1,...,6 +% fJ = (aJx^2+aJy^2+aJz^2+bJx^2+bJy^2+bJz^2-dJ)*ee + gg + +% 2*(u1*(aJx-bJx) + u2*(aJy-bJy) + u3*(aJz-bJz)) + +% 2*(v1*(aJx+bJx) + v2*(aJy+bJy) + v3*(aJz+bJz)) + +% -2*( aJx*(R11*bJx+R12*bJy+R13*bJz) + +% aJy*(R21*bJx+R22*bJy+R23*bJz) + +% aJz*(R31*bJx+R32*bJy+R33*bJz) ) ; + + f1 = (a1x^2+a1y^2+a1z^2+b1x^2+b1y^2+b1z^2-d1)*ee + gg + + 2*(u1*(a1x-b1x) + u2*(a1y-b1y) + u3*(a1z-b1z)) + + 2*(v1*(a1x+b1x) + v2*(a1y+b1y) + v3*(a1z+b1z)) + + -2*( a1x*(R11*b1x+R12*b1y+R13*b1z) + + a1y*(R21*b1x+R22*b1y+R23*b1z) + + a1z*(R31*b1x+R32*b1y+R33*b1z) ) ; + + f2 = (a2x^2+a2y^2+a2z^2+b2x^2+b2y^2+b2z^2-d2)*ee + gg + + 2*(u1*(a2x-b2x) + u2*(a2y-b2y) + u3*(a2z-b2z)) + + 2*(v1*(a2x+b2x) + v2*(a2y+b2y) + v3*(a2z+b2z)) + + -2*( a2x*(R11*b2x+R12*b2y+R13*b2z) + + a2y*(R21*b2x+R22*b2y+R23*b2z) + + a2z*(R31*b2x+R32*b2y+R33*b2z) ) ; + + f3 = (a3x^2+a3y^2+a3z^2+b3x^2+b3y^2+b3z^2-d3)*ee + gg + + 2*(u1*(a3x-b3x) + u2*(a3y-b3y) + u3*(a3z-b3z)) + + 2*(v1*(a3x+b3x) + v2*(a3y+b3y) + v3*(a3z+b3z)) + + -2*( a3x*(R11*b3x+R12*b3y+R13*b3z) + + a3y*(R21*b3x+R22*b3y+R23*b3z) + + a3z*(R31*b3x+R32*b3y+R33*b3z) ) ; + + f4 = (a4x^2+a4y^2+a4z^2+b4x^2+b4y^2+b4z^2-d4)*ee + gg + + 2*(u1*(a4x-b4x) + u2*(a4y-b4y) + u3*(a4z-b4z)) + + 2*(v1*(a4x+b4x) + v2*(a4y+b4y) + v3*(a4z+b4z)) + + -2*( a4x*(R11*b4x+R12*b4y+R13*b4z) + + a4y*(R21*b4x+R22*b4y+R23*b4z) + + a4z*(R31*b4x+R32*b4y+R33*b4z) ) ; + + f5 = (a5x^2+a5y^2+a5z^2+b5x^2+b5y^2+b5z^2-d5)*ee + gg + + 2*(u1*(a5x-b5x) + u2*(a5y-b5y) + u3*(a5z-b5z)) + + 2*(v1*(a5x+b5x) + v2*(a5y+b5y) + v3*(a5z+b5z)) + + -2*( a5x*(R11*b5x+R12*b5y+R13*b5z) + + a5y*(R21*b5x+R22*b5y+R23*b5z) + + a5z*(R31*b5x+R32*b5y+R33*b5z) ) ; + + f6 = (a6x^2+a6y^2+a6z^2+b6x^2+b6y^2+b6z^2-d6)*ee + gg + + 2*(u1*(a6x-b6x) + u2*(a6y-b6y) + u3*(a6z-b6z)) + + 2*(v1*(a6x+b6x) + v2*(a6y+b6y) + v3*(a6z+b6z)) + + -2*( a6x*(R11*b6x+R12*b6y+R13*b6z) + + a6y*(R21*b6x+R22*b6y+R23*b6z) + + a6z*(R31*b6x+R32*b6y+R33*b6z) ) ; + +END diff --git a/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyII.input b/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyII.input new file mode 100644 index 0000000..45daba5 --- /dev/null +++ b/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyII.input @@ -0,0 +1,165 @@ +% Bertini file for Griffis-Duffy Type II platform forward kinematics +% +% This special case of Stewart-Gough is Griffis-Duffy with +% base & moving triangles as equilateral and congruent, with joints at +% vertices and midpoints. Leg lengths all equal. +% +% We modify the general Stewart-Gough system to put the parameters +% on the Griffis-Duffy parameter space. +CONFIG + TrackType:1; +END + +INPUT + % Base & moving platforms are both triangles with joints + % at vertices and one joint along each edge. + % Specify this by giving random vertices and then + % interpolating to put random point on each edge. + % As the figures are planar, we set z-coordinates to zero. + constant sqrt3; + sqrt3 = 3^(1/2); + % Vertices for the stationary rigid body + constant a1x,a1y, a3x,a3y, a5x,a5y; + a1x = -sqrt3; a1y = -1; + a3x = sqrt3; a3y = -1; + a5x = 0; a5y = 2; + constant a1z,a2z,a3z,a4z,a5z,a6z; + a1z=0;a2z=0;a3z=0;a4z=0;a5z=0;a6z=0; + % Interpolating constants for sides + constant a2,a4,a6; + a2=0.5;a4=0.5;a6=0.5; + a2x = a2*a1x + (1-a2)*a3x; + a2y = a2*a1y + (1-a2)*a3y; + a4x = a4*a3x + (1-a4)*a5x; + a4y = a4*a3y + (1-a4)*a5y; + a6x = a6*a5x + (1-a6)*a1x; + a6y = a6*a5y + (1-a6)*a1y; + % Do similar for the moving rigid body + % Vertices for the stationary rigid body + constant b2x,b2y, b4x,b4y, b6x,b6y; + b2x = 0; b2y=2; + b4x = -sqrt3; b4y = -1; + b6x = sqrt3; b6y = -1; + constant b1z,b2z,b3z,b4z,b5z,b6z; + b1z=0;b2z=0;b3z=0;b4z=0;b5z=0;b6z=0; + % Interpolating constants for sides + constant b1,b3,b5; + b1=0.5;b3=0.5;b5=0.5; + b1x = b1*b6x + (1-b1)*b2x; + b1y = b1*b6y + (1-b1)*b2y; + b3x = b3*b2x + (1-b3)*b4x; + b3y = b3*b2y + (1-b3)*b4y; + b5x = b5*b4x + (1-b5)*b6x; + b5y = b5*b4y + (1-b5)*b6y; + % squared distances between point pairs + random d1; + d2=d1;d3=d1;d4=d1;d5=d1;d6=d1; + % + + % These will be the squared distance functions + function f1,f2,f3,f4,f5,f6; + % The Study quadric + function Study; + + % Use Study coordinates for the position & orientation of the moving body. + hom_variable_group e0,e1,e2,e3,g0,g1,g2,g3; + + % Let X be the 4x4 representation of quaternion (x0,x1,x2,x3) + % So + % X = [ x0 -x1 -x2 -x3 + % x1 x0 -x3 x2 + % x2 x3 x0 -x1 + % x3 -x2 x1 x0 ] + % Treat vector (v1,v2,v3) as quaternion (0,v1,v2,v3). + % We also say that Re(x) = x0 or equivalently, Re(X) = x0*I. + + % Quaternions obey the relation X*X' = |(x0,x1,x2,x3)|^2 = |X|^2 + % Let ee = E*E', gg = G*G': + ee = e0^2 + e1^2 + e2^2 +e3^2; + gg = g0^2 + g1^2 + g2^2 +g3^2; + + % After transformation, a point b = (b1,b2,b3) becomes + % Transf(b) = (E*B*E' + G*E')/ee + % with the Study quadric side condition of + % Study = Re(G*E') = 0 + Study = g0*e0 + g1*e1 + g2*e2 + g3*e3; + + % Accordingly, the governing equations are the squared distance relations + % (*) d = | (E*B*E' + G*E')/ee - A |^2 + % = [ (E*B*E' + G*E')/ee - A ]*[ (E*B'*E' + E*G')/ee - A'] + % After expanding this, several instances of E*E' = ee*I appear. After + % simplifying ee/ee = 1 (cases of ee=0 are meaningless) and then + % clearing the denominator by multiplying by ee, (*) becomes + % a quadric relation in E,G, with A,B,d considered constants. + % We apply this 6 times for d_i, a_i, b_i. + + % We simplify (*) with some vector algebra, where the following + % terms appear: + R11 = e0^2+e1^2-e2^2-e3^2; + R12 = 2*(-e0*e3+e1*e2); + R13 = 2*( e0*e2+e1*e3); + R21 = 2*( e0*e3+e2*e1); + R22 = e0^2-e1^2+e2^2-e3^2; + R23 = 2*(-e0*e1+e2*e3); + R31 = 2*(-e0*e2+e3*e1); + R32 = 2*( e0*e1+e3*e2); + R33 = e0^2-e1^2-e2^2+e3^2; + u1 = g0*e1 - e0*g1; + u2 = g0*e2 - e0*g2; + u3 = g0*e3 - e0*g3; + v1 = g2*e3 - g3*e2; + v2 = g3*e1 - g1*e3; + v3 = g1*e2 - g2*e1; + + % Now, we form the 6 distance equations. + % Write it in terms of J, then substitute J = 1,...,6 +% fJ = (aJx^2+aJy^2+aJz^2+bJx^2+bJy^2+bJz^2-dJ)*ee + gg + +% 2*(u1*(aJx-bJx) + u2*(aJy-bJy) + u3*(aJz-bJz)) + +% 2*(v1*(aJx+bJx) + v2*(aJy+bJy) + v3*(aJz+bJz)) + +% -2*( aJx*(R11*bJx+R12*bJy+R13*bJz) + +% aJy*(R21*bJx+R22*bJy+R23*bJz) + +% aJz*(R31*bJx+R32*bJy+R33*bJz) ) ; + + f1 = (a1x^2+a1y^2+a1z^2+b1x^2+b1y^2+b1z^2-d1)*ee + gg + + 2*(u1*(a1x-b1x) + u2*(a1y-b1y) + u3*(a1z-b1z)) + + 2*(v1*(a1x+b1x) + v2*(a1y+b1y) + v3*(a1z+b1z)) + + -2*( a1x*(R11*b1x+R12*b1y+R13*b1z) + + a1y*(R21*b1x+R22*b1y+R23*b1z) + + a1z*(R31*b1x+R32*b1y+R33*b1z) ) ; + + f2 = (a2x^2+a2y^2+a2z^2+b2x^2+b2y^2+b2z^2-d2)*ee + gg + + 2*(u1*(a2x-b2x) + u2*(a2y-b2y) + u3*(a2z-b2z)) + + 2*(v1*(a2x+b2x) + v2*(a2y+b2y) + v3*(a2z+b2z)) + + -2*( a2x*(R11*b2x+R12*b2y+R13*b2z) + + a2y*(R21*b2x+R22*b2y+R23*b2z) + + a2z*(R31*b2x+R32*b2y+R33*b2z) ) ; + + f3 = (a3x^2+a3y^2+a3z^2+b3x^2+b3y^2+b3z^2-d3)*ee + gg + + 2*(u1*(a3x-b3x) + u2*(a3y-b3y) + u3*(a3z-b3z)) + + 2*(v1*(a3x+b3x) + v2*(a3y+b3y) + v3*(a3z+b3z)) + + -2*( a3x*(R11*b3x+R12*b3y+R13*b3z) + + a3y*(R21*b3x+R22*b3y+R23*b3z) + + a3z*(R31*b3x+R32*b3y+R33*b3z) ) ; + + f4 = (a4x^2+a4y^2+a4z^2+b4x^2+b4y^2+b4z^2-d4)*ee + gg + + 2*(u1*(a4x-b4x) + u2*(a4y-b4y) + u3*(a4z-b4z)) + + 2*(v1*(a4x+b4x) + v2*(a4y+b4y) + v3*(a4z+b4z)) + + -2*( a4x*(R11*b4x+R12*b4y+R13*b4z) + + a4y*(R21*b4x+R22*b4y+R23*b4z) + + a4z*(R31*b4x+R32*b4y+R33*b4z) ) ; + + f5 = (a5x^2+a5y^2+a5z^2+b5x^2+b5y^2+b5z^2-d5)*ee + gg + + 2*(u1*(a5x-b5x) + u2*(a5y-b5y) + u3*(a5z-b5z)) + + 2*(v1*(a5x+b5x) + v2*(a5y+b5y) + v3*(a5z+b5z)) + + -2*( a5x*(R11*b5x+R12*b5y+R13*b5z) + + a5y*(R21*b5x+R22*b5y+R23*b5z) + + a5z*(R31*b5x+R32*b5y+R33*b5z) ) ; + + f6 = (a6x^2+a6y^2+a6z^2+b6x^2+b6y^2+b6z^2-d6)*ee + gg + + 2*(u1*(a6x-b6x) + u2*(a6y-b6y) + u3*(a6z-b6z)) + + 2*(v1*(a6x+b6x) + v2*(a6y+b6y) + v3*(a6z+b6z)) + + -2*( a6x*(R11*b6x+R12*b6y+R13*b6z) + + a6y*(R21*b6x+R22*b6y+R23*b6z) + + a6z*(R31*b6x+R32*b6y+R33*b6z) ) ; + +END diff --git a/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyILegs.input b/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyILegs.input new file mode 100644 index 0000000..cd78f2b --- /dev/null +++ b/test/data/Bertini_examples/Chap8PositiveDimensional/GriffisDuffyILegs.input @@ -0,0 +1,170 @@ +% Bertini file for Griffis-Duffy Type I platform inverse kinematics +% This file is used for computing a compatible set of leg lengths. +% +% This could be rearranged to use function evaluation for the leg +% lengths, but since we're just doing it once, we use the same +% formulas as for forward kinematics. We solve for the squared leg +% lengths as variables, which appear linearly. +% +% This special case of Stewart-Gough is Griffis-Duffy with +% base & moving triangles as equilateral, with joints at +% vertices and midpoints. Leg lengths compatible. +% +% We modify the general Stewart-Gough system to put the parameters +% on the Griffis-Duffy parameter space. +CONFIG + FinalTol:1e-40; +END + +INPUT + % Base & moving platforms are both triangles with joints + % at vertices and one joint along each edge. + % Specify this by giving random vertices and then + % interpolating to put random point on each edge. + % As the figures are planar, we set z-coordinates to zero. + constant sqrt3; + sqrt3 = 3^(1/2); + % Vertices for the stationary rigid body + constant a1x,a1y, a3x,a3y, a5x,a5y; + a1x = -sqrt3; a1y = -1; + a3x = sqrt3; a3y = -1; + a5x = 0; a5y = 2; + constant a1z,a2z,a3z,a4z,a5z,a6z; + a1z=0;a2z=0;a3z=0;a4z=0;a5z=0;a6z=0; + % Interpolating constants for sides + constant a2,a4,a6; + a2=0.5;a4=0.5;a6=0.5; + a2x = a2*a1x + (1-a2)*a3x; + a2y = a2*a1y + (1-a2)*a3y; + a4x = a4*a3x + (1-a4)*a5x; + a4y = a4*a3y + (1-a4)*a5y; + a6x = a6*a5x + (1-a6)*a1x; + a6y = a6*a5y + (1-a6)*a1y; + % Do similar for the moving rigid body + % Vertices for the stationary rigid body, scaling factor rho. + random rho; + constant b2x,b2y, b4x,b4y, b6x,b6y; + b2x = 0; b2y=rho*2; + b4x = -rho*sqrt3; b4y = -rho; + b6x = rho*sqrt3; b6y = -rho; + constant b1z,b2z,b3z,b4z,b5z,b6z; + b1z=0;b2z=0;b3z=0;b4z=0;b5z=0;b6z=0; + % Interpolating constants for sides + constant b1,b3,b5; + b1=0.5;b3=0.5;b5=0.5; + b1x = b1*b6x + (1-b1)*b2x; + b1y = b1*b6y + (1-b1)*b2y; + b3x = b3*b2x + (1-b3)*b4x; + b3y = b3*b2y + (1-b3)*b4y; + b5x = b5*b4x + (1-b5)*b6x; + b5y = b5*b4y + (1-b5)*b6y; + % Make a random platform location in Study coordinates + random e0,e1,e2,e3,g0,g1,g2; + + % These will be the squared distance functions + function f1,f2,f3,f4,f5,f6; + % Function to print out rho value + function RHO; + variable_group r,d1,d2,d3,d4,d5,d6; + + RHO = r-rho; + + % compute g3 to satisfy Study quadric + g3 = -(g0*e0 + g1*e1 + g2*e2)/e3; + + % Let X be the 4x4 representation of quaternion (x0,x1,x2,x3) + % So + % X = [ x0 -x1 -x2 -x3 + % x1 x0 -x3 x2 + % x2 x3 x0 -x1 + % x3 -x2 x1 x0 ] + % Treat vector (v1,v2,v3) as quaternion (0,v1,v2,v3). + % We also say that Re(x) = x0 or equivalently, Re(X) = x0*I. + + % Quaternions obey the relation X*X' = |(x0,x1,x2,x3)|^2 = |X|^2 + % Let ee = E*E', gg = G*G': + ee = e0^2 + e1^2 + e2^2 +e3^2; + gg = g0^2 + g1^2 + g2^2 +g3^2; + + % After transformation, a point b = (b1,b2,b3) becomes + % Transf(b) = (E*B*E' + G*E')/ee + + % Accordingly, the governing equations are the squared distance relations + % (*) d = | (E*B*E' + G*E')/ee - A |^2 + % = [ (E*B*E' + G*E')/ee - A ]*[ (E*B'*E' + E*G')/ee - A'] + % After expanding this, several instances of E*E' = ee*I appear. After + % simplifying ee/ee = 1 (cases of ee=0 are meaningless) and then + % clearing the denominator by multiplying by ee, (*) becomes + % a quadric relation in E,G, with A,B,d considered constants. + % We apply this 6 times for d_i, a_i, b_i. + + % We simplify (*) with some vector algebra, where the following + % terms appear: + R11 = e0^2+e1^2-e2^2-e3^2; + R12 = 2*(-e0*e3+e1*e2); + R13 = 2*( e0*e2+e1*e3); + R21 = 2*( e0*e3+e2*e1); + R22 = e0^2-e1^2+e2^2-e3^2; + R23 = 2*(-e0*e1+e2*e3); + R31 = 2*(-e0*e2+e3*e1); + R32 = 2*( e0*e1+e3*e2); + R33 = e0^2-e1^2-e2^2+e3^2; + u1 = g0*e1 - e0*g1; + u2 = g0*e2 - e0*g2; + u3 = g0*e3 - e0*g3; + v1 = g2*e3 - g3*e2; + v2 = g3*e1 - g1*e3; + v3 = g1*e2 - g2*e1; + + % Now, we form the 6 distance equations. + % Write it in terms of J, then substitute J = 1,...,6 +% fJ = (aJx^2+aJy^2+aJz^2+bJx^2+bJy^2+bJz^2-dJ)*ee + gg + +% 2*(u1*(aJx-bJx) + u2*(aJy-bJy) + u3*(aJz-bJz)) + +% 2*(v1*(aJx+bJx) + v2*(aJy+bJy) + v3*(aJz+bJz)) + +% 2*( aJx*(R11*bJx+R12*bJy+R13*bJz) + +% aJy*(R21*bJx+R22*bJy+R23*bJz) + +% aJz*(R31*bJx+R32*bJy+R33*bJz) ) ; + + f1 = (a1x^2+a1y^2+a1z^2+b1x^2+b1y^2+b1z^2-d1)*ee + gg + + 2*(u1*(a1x-b1x) + u2*(a1y-b1y) + u3*(a1z-b1z)) + + 2*(v1*(a1x+b1x) + v2*(a1y+b1y) + v3*(a1z+b1z)) + + 2*( a1x*(R11*b1x+R12*b1y+R13*b1z) + + a1y*(R21*b1x+R22*b1y+R23*b1z) + + a1z*(R31*b1x+R32*b1y+R33*b1z) ) ; + + f2 = (a2x^2+a2y^2+a2z^2+b2x^2+b2y^2+b2z^2-d2)*ee + gg + + 2*(u1*(a2x-b2x) + u2*(a2y-b2y) + u3*(a2z-b2z)) + + 2*(v1*(a2x+b2x) + v2*(a2y+b2y) + v3*(a2z+b2z)) + + 2*( a2x*(R11*b2x+R12*b2y+R13*b2z) + + a2y*(R21*b2x+R22*b2y+R23*b2z) + + a2z*(R31*b2x+R32*b2y+R33*b2z) ) ; + + f3 = (a3x^2+a3y^2+a3z^2+b3x^2+b3y^2+b3z^2-d3)*ee + gg + + 2*(u1*(a3x-b3x) + u2*(a3y-b3y) + u3*(a3z-b3z)) + + 2*(v1*(a3x+b3x) + v2*(a3y+b3y) + v3*(a3z+b3z)) + + 2*( a3x*(R11*b3x+R12*b3y+R13*b3z) + + a3y*(R21*b3x+R22*b3y+R23*b3z) + + a3z*(R31*b3x+R32*b3y+R33*b3z) ) ; + + f4 = (a4x^2+a4y^2+a4z^2+b4x^2+b4y^2+b4z^2-d4)*ee + gg + + 2*(u1*(a4x-b4x) + u2*(a4y-b4y) + u3*(a4z-b4z)) + + 2*(v1*(a4x+b4x) + v2*(a4y+b4y) + v3*(a4z+b4z)) + + 2*( a4x*(R11*b4x+R12*b4y+R13*b4z) + + a4y*(R21*b4x+R22*b4y+R23*b4z) + + a4z*(R31*b4x+R32*b4y+R33*b4z) ) ; + + f5 = (a5x^2+a5y^2+a5z^2+b5x^2+b5y^2+b5z^2-d5)*ee + gg + + 2*(u1*(a5x-b5x) + u2*(a5y-b5y) + u3*(a5z-b5z)) + + 2*(v1*(a5x+b5x) + v2*(a5y+b5y) + v3*(a5z+b5z)) + + 2*( a5x*(R11*b5x+R12*b5y+R13*b5z) + + a5y*(R21*b5x+R22*b5y+R23*b5z) + + a5z*(R31*b5x+R32*b5y+R33*b5z) ) ; + + f6 = (a6x^2+a6y^2+a6z^2+b6x^2+b6y^2+b6z^2-d6)*ee + gg + + 2*(u1*(a6x-b6x) + u2*(a6y-b6y) + u3*(a6z-b6z)) + + 2*(v1*(a6x+b6x) + v2*(a6y+b6y) + v3*(a6z+b6z)) + + 2*( a6x*(R11*b6x+R12*b6y+R13*b6z) + + a6y*(R21*b6x+R22*b6y+R23*b6z) + + a6z*(R31*b6x+R32*b6y+R33*b6z) ) ; + +END diff --git a/test/data/Bertini_examples/Chap8PositiveDimensional/Illustrative.input b/test/data/Bertini_examples/Chap8PositiveDimensional/Illustrative.input new file mode 100644 index 0000000..e58ee2b --- /dev/null +++ b/test/data/Bertini_examples/Chap8PositiveDimensional/Illustrative.input @@ -0,0 +1,14 @@ +% Illustrative.input +CONFIG + TrackType:1; +END; +INPUT + variable_group x,y,z; + function f1,f2,f3; + S = x^2+y^2+z^2-1; + T = y-x^2; + U = z-x^3; + f1 = T*S*(x-2); + f2 = U*S*(y-2); + f3 = T*U*S*(z-2); +END; diff --git a/test/data/Bertini_examples/Chap8PositiveDimensional/SmallConstant.input b/test/data/Bertini_examples/Chap8PositiveDimensional/SmallConstant.input new file mode 100644 index 0000000..73dd65b --- /dev/null +++ b/test/data/Bertini_examples/Chap8PositiveDimensional/SmallConstant.input @@ -0,0 +1,22 @@ +% SmallConstant.input +% +% When the constant is bigger than FinalTol, this +% looks like one irreducible component. But when +% it is small enough, it is judged to factor into +% two lines. +% +% If the constant really is supposed to be nonzero, +% the problem should be re-scaled to make this +% apparent. +% +% The default FinalTol is 1e-11. Play with +% changing FinalTol and the constant to see what +% happens. +CONFIG + TrackType:1; +END; +INPUT + variable_group x,y; + function f; + f = x*y-1e-11; +END; diff --git a/test/data/Bertini_examples/Chap8PositiveDimensional/ThreeLines.input b/test/data/Bertini_examples/Chap8PositiveDimensional/ThreeLines.input new file mode 100644 index 0000000..4f44d8c --- /dev/null +++ b/test/data/Bertini_examples/Chap8PositiveDimensional/ThreeLines.input @@ -0,0 +1,11 @@ +% ThreeLines.input +CONFIG + TrackType:1; +END; +INPUT + variable_group x,y,z; + function f,g; + + f = x*z+y; + g = y*z+x; +END; diff --git a/test/data/Bertini_examples/Chap9WitnessGeneration/._.DS_Store b/test/data/Bertini_examples/Chap9WitnessGeneration/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_DimByDim.input b/test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_DimByDim.input new file mode 100644 index 0000000..9f782e7 --- /dev/null +++ b/test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_DimByDim.input @@ -0,0 +1,20 @@ +% Adjacent Minors dimension-by-dimension +% +CONFIG + TrackType:1; + WitnessGenType:1; % dimension-by-dimension + WitnessSupersetOnly:1; % only compute a witness point superset +END; +INPUT + function f1,f2,f3,f4,f5,f6; + variable_group x_[11],x_[12],x_[13],x_[14], + x_[21],x_[22],x_[23],x_[24], + x_[31],x_[32],x_[33],x_[34]; + + f1 = x_[11]*x_[22]-x_[12]*x_[21]; + f2 = x_[12]*x_[23]-x_[13]*x_[22]; + f3 = x_[13]*x_[24]-x_[14]*x_[23]; + f4 = x_[21]*x_[32]-x_[22]*x_[31]; + f5 = x_[22]*x_[33]-x_[23]*x_[32]; + f6 = x_[23]*x_[34]-x_[24]*x_[33]; +END; diff --git a/test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_classical.input b/test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_classical.input new file mode 100644 index 0000000..b43bd76 --- /dev/null +++ b/test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_classical.input @@ -0,0 +1,20 @@ +% Adjacent Minors: witness generation by classical cascade +% +CONFIG + TrackType:1; + WitnessGenType:0; % classical cascade + WitnessSupersetOnly:1; % only compute a witness point superset +END; +INPUT + function f1,f2,f3,f4,f5,f6; + variable_group x_[11],x_[12],x_[13],x_[14], + x_[21],x_[22],x_[23],x_[24], + x_[31],x_[32],x_[33],x_[34]; + + f1 = x_[11]*x_[22]-x_[12]*x_[21]; + f2 = x_[12]*x_[23]-x_[13]*x_[22]; + f3 = x_[13]*x_[24]-x_[14]*x_[23]; + f4 = x_[21]*x_[32]-x_[22]*x_[31]; + f5 = x_[22]*x_[33]-x_[23]*x_[32]; + f6 = x_[23]*x_[34]-x_[24]*x_[33]; +END; diff --git a/test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_regenCascade.input b/test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_regenCascade.input new file mode 100644 index 0000000..1b920fa --- /dev/null +++ b/test/data/Bertini_examples/Chap9WitnessGeneration/AdjacentMinors_regenCascade.input @@ -0,0 +1,20 @@ +% Adjacent Minors: witness generation by regenerative cascade +% +CONFIG + TrackType:1; + WitnessGenType:2; % regenerative cascade (could omit, as this is the default) + WitnessSupersetOnly:1; % only compute a witness point superset +END; +INPUT + function f1,f2,f3,f4,f5,f6; + variable_group x_[11],x_[12],x_[13],x_[14], + x_[21],x_[22],x_[23],x_[24], + x_[31],x_[32],x_[33],x_[34]; + + f1 = x_[11]*x_[22]-x_[12]*x_[21]; + f2 = x_[12]*x_[23]-x_[13]*x_[22]; + f3 = x_[13]*x_[24]-x_[14]*x_[23]; + f4 = x_[21]*x_[32]-x_[22]*x_[31]; + f5 = x_[22]*x_[33]-x_[23]*x_[32]; + f6 = x_[23]*x_[34]-x_[24]*x_[33]; +END; diff --git a/test/data/Bertini_examples/README.md b/test/data/Bertini_examples/README.md new file mode 100644 index 0000000..adf3a8c --- /dev/null +++ b/test/data/Bertini_examples/README.md @@ -0,0 +1,4 @@ +# Bertini book examples + +The examples in this folder are all taken from *Numerically solving polynomial systems with Bertini*. +They may be obtained [here](https://bertini.nd.edu/BertiniExamples/). \ No newline at end of file diff --git a/test/data/README.md b/test/data/README.md new file mode 100644 index 0000000..5bb6260 --- /dev/null +++ b/test/data/README.md @@ -0,0 +1,4 @@ +# Examples + +Examples in this directory, with the exception of the `Bertini_examples` subdirectory and `zero_dim/parameter_homotopy`, +may all be obtained from the [Bertini tarball](https://bertini.nd.edu/download.html). \ No newline at end of file diff --git a/test/test_io.py b/test/test_io.py index 6b402ec..a4502c7 100644 --- a/test/test_io.py +++ b/test/test_io.py @@ -1,49 +1,44 @@ from context import op, ZERO_DIM_BASE, POS_DIM_BASE -from collections import OrderedDict - -import numpy as np - -from naglib.bertini.io import read_input_file, read_points_file +from naglib.bertini.io import read_input_file from naglib.bertini.input_file import BertiniInput, BertiniConfig def is_empty(x): return len(x) == 0 -# TODO: there's a problem when running both of these tests which causes the BertiniInput in test2 -# to share its variable group with that of test1. I have no idea why. -# def test_read_input1(): -# config, inputs, misclines = read_input_file(op.join(POS_DIM_BASE, "sampling", "input")) -# -# assert isinstance(config, BertiniConfig) -# assert config.tracktype == 2 -# assert config.mptype == 2 -# assert config.precision == 96 -# assert config.coeffbound == 1000 -# assert config.degreebound == 5 -# assert config.ampmaxprec == 1024 -# assert config.parameterhomotopy == 0 -# assert config.randomseed == 0 -# -# assert isinstance(inputs, BertiniInput) -# assert is_empty(inputs.constant) -# assert is_empty(inputs.variable) -# assert is_empty(inputs.hom_variable_group) -# assert is_empty(inputs.subfunction) -# assert is_empty(inputs.parameter) -# assert is_empty(inputs.random) -# assert is_empty(inputs.random_real) -# assert is_empty(inputs.pathvariable) -# assert inputs.ndims == 3 -# assert len(inputs.variable_group) == 1 -# assert inputs.variable_group[0] == ["x", "y", "z"] -# assert len(inputs.function) == 3 -# assert inputs.function["f1"] == "(y-x^2)*(x^2+y^2+z^2-1)*(x-0.5)" -# assert inputs.function["f2"] == "(z-x^3)*(x^2+y^2+z^2-1)*(y-0.5)" -# assert inputs.function["f3"] == "(y-x^2)*(z-x^3)*(x^2+y^2+z^2-1)*(z-0.5)" -# -# assert isinstance(misclines, list) and len(misclines) == 0 + +def test_read_input1(): + config, inputs, misclines = read_input_file(op.join(POS_DIM_BASE, "sampling", "input")) + + assert isinstance(config, BertiniConfig) + assert config.tracktype == 2 + assert config.mptype == 2 + assert config.precision == 96 + assert config.coeffbound == 1000 + assert config.degreebound == 5 + assert config.ampmaxprec == 1024 + assert config.parameterhomotopy == 0 + assert config.randomseed == 0 + + assert isinstance(inputs, BertiniInput) + assert is_empty(inputs.constant) + assert is_empty(inputs.variable) + assert is_empty(inputs.hom_variable_group) + assert is_empty(inputs.subfunction) + assert is_empty(inputs.parameter) + assert is_empty(inputs.random) + assert is_empty(inputs.random_real) + assert is_empty(inputs.pathvariable) + assert inputs.ndims == 3 + assert len(inputs.variable_group) == 1 + assert inputs.variable_group[0] == ["x", "y", "z"] + assert len(inputs.function) == 3 + assert inputs.function["f1"] == "(y-x^2)*(x^2+y^2+z^2-1)*(x-0.5)" + assert inputs.function["f2"] == "(z-x^3)*(x^2+y^2+z^2-1)*(y-0.5)" + assert inputs.function["f3"] == "(y-x^2)*(z-x^3)*(x^2+y^2+z^2-1)*(z-0.5)" + + assert isinstance(misclines, list) and len(misclines) == 0 def test_read_input2(): From 0a51584306b69c6b8d16054b585c9c3cf0dd43a3 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Sat, 29 Jun 2019 13:58:57 -0400 Subject: [PATCH 15/25] check for [real_]finite_solutions before trying to read it --- naglib/bertini/run.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 2d81da6..0b4094e 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -125,12 +125,20 @@ def _recover_data(self): result = read_main_data_file(op.join(self.dirname, "main_data")) if self.tracktype == self.config.TZERODIM: - result.finite_solutions = read_points_file(op.join(self.dirname, "finite_solutions"), - multi=self.config.mptype != 0) + if op.isfile(op.join(self.dirname), "finite_solutions"): + result.finite_solutions = read_points_file(op.join(self.dirname, "finite_solutions"), + multi=self.config.mptype != 0) + else: + result.finite_solutions = np.array(0, dtype=np.complex) + + if op.isfile(op.join(self.dirname), "real_finite_solutions"): + result.real_finite_solutions = read_points_file(op.join(self.dirname, "real_finite_solutions"), + multi=self.config.mptype != 0) + else: + result.real_finite_solutions = np.array(0, dtype=np.complex) + result.nonsingular_solutions = read_points_file(op.join(self.dirname, "nonsingular_solutions"), multi=self.config.mptype != 0) - result.real_finite_solutions = read_points_file(op.join(self.dirname, "real_finite_solutions"), - multi=self.config.mptype != 0) result.singular_solutions = read_points_file(op.join(self.dirname, "singular_solutions"), multi=self.config.mptype != 0) From 090249a384c7eee8c0699cd14e6370aeadefcd3b Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Sat, 29 Jun 2019 14:00:52 -0400 Subject: [PATCH 16/25] do not commit in haste --- naglib/bertini/run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 0b4094e..843575a 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -125,13 +125,13 @@ def _recover_data(self): result = read_main_data_file(op.join(self.dirname, "main_data")) if self.tracktype == self.config.TZERODIM: - if op.isfile(op.join(self.dirname), "finite_solutions"): + if op.isfile(op.join(self.dirname, "finite_solutions")): result.finite_solutions = read_points_file(op.join(self.dirname, "finite_solutions"), multi=self.config.mptype != 0) else: result.finite_solutions = np.array(0, dtype=np.complex) - if op.isfile(op.join(self.dirname), "real_finite_solutions"): + if op.isfile(op.join(self.dirname, "real_finite_solutions")): result.real_finite_solutions = read_points_file(op.join(self.dirname, "real_finite_solutions"), multi=self.config.mptype != 0) else: From 10a98485c73c07a3b06b80d5f0f81cf2b4fecf8e Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Sat, 29 Jun 2019 14:10:49 -0400 Subject: [PATCH 17/25] write out start on parameterhomotopy:2 --- naglib/bertini/run.py | 1 + 1 file changed, 1 insertion(+) diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 843575a..71b26cd 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -328,6 +328,7 @@ def setup(self, dirname: str = None): if self.config.parameterhomotopy == 2: write_points_file(self.start_parameters.reshape(1, self.start_parameters.size), op.join(self._dirname, "start_parameters")) write_points_file(self.final_parameters.reshape(1, self.final_parameters.size), op.join(self._dirname, "final_parameters")) + write_points_file(self.start, op.join(self._dirname, "start")) @property def bertini(self): From dce63c7715fca9fe35388050292eb0105258924f Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Sat, 29 Jun 2019 14:23:12 -0400 Subject: [PATCH 18/25] needs start points all right --- naglib/bertini/input_file.py | 5 +++-- naglib/bertini/io.py | 14 ++++++++++++-- naglib/bertini/run.py | 3 ++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/naglib/bertini/input_file.py b/naglib/bertini/input_file.py index 9e31579..2ae2623 100644 --- a/naglib/bertini/input_file.py +++ b/naglib/bertini/input_file.py @@ -124,8 +124,9 @@ def needs_component(self): self.TPROJECT, self.TREGENEXT) def needs_start_points(self): - return self.tracktype in (self.TEVALP, self.TEVALPJ, self.TNEWTP, - self.TNEWTPJ, self.TMEMTEST, self.TISOSTAB) + nsp = self.tracktype in (self.TEVALP, self.TEVALPJ, self.TNEWTP, self.TNEWTPJ, self.TMEMTEST, + self.TISOSTAB) or self.parameterhomotopy == 2 + return nsp def needs_sample_count(self): return self.tracktype == self.TSAMPLE diff --git a/naglib/bertini/io.py b/naglib/bertini/io.py index 68d8e72..948018e 100644 --- a/naglib/bertini/io.py +++ b/naglib/bertini/io.py @@ -15,14 +15,16 @@ class BertiniResult: - def __init__(self, **kwargs): + def __init__(self, dirname, **kwargs): """The output of a Bertini run. Parameters ---------- + dirname : str + Path to directory where run was done. kwargs """ - pass + self._dirname = dirname @property def config(self): @@ -34,6 +36,14 @@ def config(self, val): assert isinstance(val, BertiniConfig) self._config = val + @property + def dirname(self): + return self._dirname + @dirname.setter + def dirname(self, val): + assert op.isdir(val) + self._dirname = val + @property def inputs(self): """Inputs needed to reproduce the run.""" diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 71b26cd..315b24d 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -82,7 +82,7 @@ def __init__(self, config, inputs, **kwargs): if inputs.parameter and config.parameterhomotopy == 0: raise ValueError("your system has parameters but you have not specified a parameter homotopy") - # parameterhomotopy:2 requires start and final params + # parameterhomotopy:2 requires start and final params, also start points if config.parameterhomotopy == 2: if "start_parameters" in kwargs: self.start_parameters = kwargs["start_parameters"] @@ -93,6 +93,7 @@ def __init__(self, config, inputs, **kwargs): else: raise ValueError("you have selected parameterhomotopy:2 but you have not given final parameters") + if "bertini_path" in kwargs: if not op.isfile(kwargs["bertini_path"]): raise OSError(f"didn't find Bertini at '{kwargs['bertini_path']}'") From 8a3552696759fdb665214f51bac9b87104dc94db Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Sat, 29 Jun 2019 14:25:40 -0400 Subject: [PATCH 19/25] BertiniResult takes a dirname now --- naglib/bertini/io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/naglib/bertini/io.py b/naglib/bertini/io.py index 948018e..fadd003 100644 --- a/naglib/bertini/io.py +++ b/naglib/bertini/io.py @@ -224,7 +224,7 @@ def read_main_data_file(main_data_file: str) -> BertiniResult: if not op.isfile(main_data_file): raise IOError(f"Main data file '{main_data_file}' not found") - result = BertiniResult() + result = BertiniResult(op.dirname(main_data_file)) with open(main_data_file, "r") as fh: line = fh.readline() From e65d2998d6a5a86fb8c85ab94281f99a754595e4 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Sat, 29 Jun 2019 14:32:59 -0400 Subject: [PATCH 20/25] inputs has ndims property, not config --- naglib/bertini/run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 315b24d..868ea4d 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -388,8 +388,8 @@ def start(self, val): raise TypeError("expected a numpy array") if val.ndim == 1: val = val.reshape(val.size, 1) - if val.shape[0] != self.config.ndims: - raise ValueError(f"expected points of dimension {self.config.ndims} but you specified {val.shape[0]}") + if val.shape[0] != self.inputs.ndims: + raise ValueError(f"expected points of dimension {self.inputs.ndims} but you specified {val.shape[0]}") self._start = val.astype(np.complex) From 62025f1c324715b3d6f14ef10009fdbc4d83a28c Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Sat, 6 Jul 2019 08:56:24 -0400 Subject: [PATCH 21/25] add finaltol and imagthreshold (default values are incorrect, need a reference) --- naglib/bertini/input_file.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/naglib/bertini/input_file.py b/naglib/bertini/input_file.py index 2ae2623..776d452 100644 --- a/naglib/bertini/input_file.py +++ b/naglib/bertini/input_file.py @@ -33,6 +33,10 @@ def _ordereddict_of_type(obj, dtype): "is valid": lambda x: isinstance(x, float) and x > 0}, ampmaxprec={"default": 1024, "is valid": lambda x: isinstance(x, int) and x >= 64}, + finaltol={"default": 1., + "is valid": lambda x: isinstance(x, Number) and x > 0}, + imagthreshold={"default": 1., + "is valid": lambda x: isinstance(x, Number) and x > 0}, parameterhomotopy={"default": 0, "is valid": lambda x: x in range(0, 3)}, randomseed={"default": 0, @@ -167,6 +171,28 @@ def degreebound(self, val): raise ValueError("degreebound must be a positive double") self._degreebound = val + @property + def finaltol(self): + return self._finaltol + + @finaltol.setter + def finaltol(self, val): + val, is_valid = _validate_param("finaltol", val) + if not is_valid: + raise ValueError("finaltol must be a positive double") + self._finaltol = val + + @property + def imagthreshold(self): + return self._finaltol + + @imagthreshold.setter + def imagthreshold(self, val): + val, is_valid = _validate_param("imagthreshold", val) + if not is_valid: + raise ValueError("imagthreshold must be a positive double") + self._imagthreshold = val + @property def mptype(self): return self._mptype From 5264c6899cc507e1796afad0246e8171ddb4f90c Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Sat, 6 Jul 2019 08:57:50 -0400 Subject: [PATCH 22/25] use cwd argument rather than changing to working dir --- naglib/bertini/run.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/naglib/bertini/run.py b/naglib/bertini/run.py index 868ea4d..b0bb808 100644 --- a/naglib/bertini/run.py +++ b/naglib/bertini/run.py @@ -276,13 +276,12 @@ def run(self, dirname: str = None, tee: bool = True): else: stdin = None - os.chdir(self.dirname) if stdin is not None: stdin = open(stdin, "r") try: proc = subprocess.Popen(arg, stdin=stdin, stdout=subprocess.PIPE, - universal_newlines=True) + cwd=self.dirname, universal_newlines=True) except subprocess.CalledProcessError as e: msg = extract_error_message(e.output) raise BertiniError(msg) From d554af3f9adc6327113af982081bd94a181fc3d0 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Tue, 30 Mar 2021 10:25:49 -0400 Subject: [PATCH 23/25] some rearranging --- .gitignore | 257 +++++++++++++++++- .idea/.gitignore | 8 + .idea/.name | 1 + .idea/inspectionProfiles/Project_Default.xml | 6 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + .idea/other.xml | 7 + .idea/python-bertini.iml | 13 + .idea/vcs.xml | 6 + {naglib => bertini}/__init__.py | 0 {naglib => bertini}/exceptions.py | 0 {naglib/bertini => bertini/io}/__init__.py | 0 bertini/io/bertini_result.py | 0 {naglib/bertini => bertini/io}/input_file.py | 0 {naglib/bertini => bertini/io}/io.py | 4 +- {naglib => bertini}/release.py | 0 {naglib/bertini => bertini}/run.py | 15 +- environment.yml | 2 +- requirements.txt | 6 +- setup.py | 4 +- test/data/README.md | 2 +- test/test_input_file.py | 2 +- test/test_io.py | 4 +- test/test_parameter_homotopy.py | 6 +- 25 files changed, 334 insertions(+), 27 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/other.xml create mode 100644 .idea/python-bertini.iml create mode 100644 .idea/vcs.xml rename {naglib => bertini}/__init__.py (100%) rename {naglib => bertini}/exceptions.py (100%) rename {naglib/bertini => bertini/io}/__init__.py (100%) create mode 100644 bertini/io/bertini_result.py rename {naglib/bertini => bertini/io}/input_file.py (100%) rename {naglib/bertini => bertini/io}/io.py (99%) rename {naglib => bertini}/release.py (100%) rename {naglib/bertini => bertini}/run.py (96%) diff --git a/.gitignore b/.gitignore index a4b870d..19f729d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,257 @@ -.idea/ -.spyproject/ -__pycache__ +# Created by https://www.toptal.com/developers/gitignore/api/python,pycharm +# Edit at https://www.toptal.com/developers/gitignore?templates=python,pycharm + +### PyCharm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ *.egg-info/ -.DS_Store +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +pytestdebug.log + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ +doc/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +#poetry.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +# .env +.env/ +.venv/ +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +pythonenv* + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# operating system-related files +*.DS_Store #file properties cache/storage on macOS +Thumbs.db #thumbnail cache on Windows + +# profiling data +.prof + + +# End of https://www.toptal.com/developers/gitignore/api/python,pycharm # test output test/data/zero_dim/**/failed_paths diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..3b1f3d3 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +python-bertini \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0eca9f2 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..97acf69 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/other.xml b/.idea/other.xml new file mode 100644 index 0000000..640fd80 --- /dev/null +++ b/.idea/other.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/python-bertini.iml b/.idea/python-bertini.iml new file mode 100644 index 0000000..1d2303c --- /dev/null +++ b/.idea/python-bertini.iml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/naglib/__init__.py b/bertini/__init__.py similarity index 100% rename from naglib/__init__.py rename to bertini/__init__.py diff --git a/naglib/exceptions.py b/bertini/exceptions.py similarity index 100% rename from naglib/exceptions.py rename to bertini/exceptions.py diff --git a/naglib/bertini/__init__.py b/bertini/io/__init__.py similarity index 100% rename from naglib/bertini/__init__.py rename to bertini/io/__init__.py diff --git a/bertini/io/bertini_result.py b/bertini/io/bertini_result.py new file mode 100644 index 0000000..e69de29 diff --git a/naglib/bertini/input_file.py b/bertini/io/input_file.py similarity index 100% rename from naglib/bertini/input_file.py rename to bertini/io/input_file.py diff --git a/naglib/bertini/io.py b/bertini/io/io.py similarity index 99% rename from naglib/bertini/io.py rename to bertini/io/io.py index fadd003..c6d87e8 100644 --- a/naglib/bertini/io.py +++ b/bertini/io/io.py @@ -10,8 +10,8 @@ import mpmath as mp import numpy as np -from naglib.bertini.input_file import BertiniConfig, BertiniInput -from naglib.exceptions import UnclassifiedException +from bertini.io.input_file import BertiniConfig, BertiniInput +from bertini.exceptions import UnclassifiedException class BertiniResult: diff --git a/naglib/release.py b/bertini/release.py similarity index 100% rename from naglib/release.py rename to bertini/release.py diff --git a/naglib/bertini/run.py b/bertini/run.py similarity index 96% rename from naglib/bertini/run.py rename to bertini/run.py index b0bb808..d834891 100644 --- a/naglib/bertini/run.py +++ b/bertini/run.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import os import os.path as op import multiprocessing @@ -10,10 +9,10 @@ from typing import Union -from naglib.bertini.input_file import BertiniConfig, BertiniInput -from naglib.bertini.io import (read_input_file, read_main_data_file, read_points_file, read_witness_data_file, - write_input_file, write_points_file, extract_error_message) -from naglib.exceptions import BertiniError +from bertini.io.input_file import BertiniConfig, BertiniInput +from bertini.io.io import (read_input_file, read_main_data_file, read_points_file, read_witness_data_file, + write_input_file, write_points_file, extract_error_message) +from bertini.exceptions import BertiniError def _which(exe: str) -> Union[str, None]: @@ -99,9 +98,9 @@ def __init__(self, config, inputs, **kwargs): raise OSError(f"didn't find Bertini at '{kwargs['bertini_path']}'") self._bertini = kwargs["bertini_path"] else: - bertini = _which("bertini") + bertini = _which("io") if bertini is None: - raise OSError("couldn't find a bertini executable and you didn't specify one") + raise OSError("couldn't find a io executable and you didn't specify one") self._bertini = bertini if "mpi_path" in kwargs: @@ -176,7 +175,7 @@ def _recover_input(self): return inlines # def _write_files(self): - # from naglib.bertini.fileutils import fprint + # from io.io.fileutils import fprint # # tracktype = self._tracktype # dirname = self._dirname diff --git a/environment.yml b/environment.yml index 979e499..8f95ac6 100644 --- a/environment.yml +++ b/environment.yml @@ -1,4 +1,4 @@ -name: naglib +name: bertini channels: - defaults - conda-forge diff --git a/requirements.txt b/requirements.txt index a5dabd9..cdde399 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -mpmath==1.1.0 -numpy==1.16.4 -pytest==4.6.3 \ No newline at end of file +mpmath +numpy +pytest \ No newline at end of file diff --git a/setup.py b/setup.py index 50a2f8a..78a6998 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,9 @@ from setuptools import setup setup( - name='naglib', + name='io', version='0.1.0', - packages=['naglib', 'naglib.bertini'], + packages=['io', 'io.io'], url='https://github.com/aliddell/naglib', license='BSD', author='Alan', diff --git a/test/data/README.md b/test/data/README.md index 5bb6260..696923f 100644 --- a/test/data/README.md +++ b/test/data/README.md @@ -1,4 +1,4 @@ # Examples -Examples in this directory, with the exception of the `Bertini_examples` subdirectory and `zero_dim/parameter_homotopy`, +Examples in this directory, except the `Bertini_examples` subdirectory and `zero_dim/parameter_homotopy`, may all be obtained from the [Bertini tarball](https://bertini.nd.edu/download.html). \ No newline at end of file diff --git a/test/test_input_file.py b/test/test_input_file.py index bcfebcd..476e3d8 100644 --- a/test/test_input_file.py +++ b/test/test_input_file.py @@ -2,7 +2,7 @@ from collections import OrderedDict -from naglib.bertini.input_file import BertiniInput, BertiniConfig +from bertini.io.input_file import BertiniInput, BertiniConfig def test_inputs_parameter_homotopy(): diff --git a/test/test_io.py b/test/test_io.py index a4502c7..2cfef5b 100644 --- a/test/test_io.py +++ b/test/test_io.py @@ -1,7 +1,7 @@ from context import op, ZERO_DIM_BASE, POS_DIM_BASE -from naglib.bertini.io import read_input_file -from naglib.bertini.input_file import BertiniInput, BertiniConfig +from bertini.io.io import read_input_file +from bertini.io.input_file import BertiniInput, BertiniConfig def is_empty(x): diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index 58b9839..cbead45 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -4,9 +4,9 @@ import numpy as np -from naglib.bertini.io import write_input_file -from naglib.bertini.run import BertiniRun -from naglib.bertini.input_file import BertiniInput, BertiniConfig +from bertini.io.io import write_input_file +from bertini.run import BertiniRun +from bertini.io.input_file import BertiniInput, BertiniConfig class TestParameterHomotopy: From 56be90c773be064e1e25cc00ff48e25bf36d5553 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Wed, 31 Mar 2021 10:45:37 -0400 Subject: [PATCH 24/25] can count real solutions to Kuramoto3 in this state --- .idea/misc.xml | 2 +- .idea/python-bertini.iml | 4 +- bertini/io/input_file/__init__.py | 2 + bertini/io/input_file/config_section.py | 185 ++++++++++++++++++ .../input_section.py} | 174 +--------------- bertini/io/{bertini_result.py => reader.py} | 0 bertini/io/result.py | 45 +++++ bertini/io/{io.py => utils.py} | 45 +---- bertini/run.py | 21 +- environment.yml | 3 +- requirements.txt | 3 +- test/{context.py => conftest.py} | 0 test/test_input_file.py | 4 +- test/test_io.py | 7 +- test/test_parameter_homotopy.py | 7 +- 15 files changed, 264 insertions(+), 238 deletions(-) create mode 100644 bertini/io/input_file/__init__.py create mode 100644 bertini/io/input_file/config_section.py rename bertini/io/{input_file.py => input_file/input_section.py} (65%) rename bertini/io/{bertini_result.py => reader.py} (100%) create mode 100644 bertini/io/result.py rename bertini/io/{io.py => utils.py} (95%) rename test/{context.py => conftest.py} (100%) diff --git a/.idea/misc.xml b/.idea/misc.xml index 0eca9f2..ad684c6 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/.idea/python-bertini.iml b/.idea/python-bertini.iml index 1d2303c..4323654 100644 --- a/.idea/python-bertini.iml +++ b/.idea/python-bertini.iml @@ -1,8 +1,8 @@ - - + + diff --git a/bertini/io/input_file/__init__.py b/bertini/io/input_file/__init__.py new file mode 100644 index 0000000..50b6cb3 --- /dev/null +++ b/bertini/io/input_file/__init__.py @@ -0,0 +1,2 @@ +from .config_section import BertiniConfig +from .input_section import BertiniInput diff --git a/bertini/io/input_file/config_section.py b/bertini/io/input_file/config_section.py new file mode 100644 index 0000000..724e034 --- /dev/null +++ b/bertini/io/input_file/config_section.py @@ -0,0 +1,185 @@ +from copy import deepcopy + +from bertini.io.input_file.input_section import PARAMETERS, _validate_param + + +class BertiniConfig(object): + TEVALP = -4 + TEVALPJ = -3 + TNEWTP = -2 + TNEWTPJ = -1 + TZERODIM = 0 # parallel + TPOSDIM = 1 # parallel + TSAMPLE = 2 + TMEMTEST = 3 + TPRINTWS = 4 + TPROJECT = 5 + TISOSTAB = 6 + TREGENEXT = 7 # parallel + + def __init__(self, **kwargs): + for arg_name in PARAMETERS: + if arg_name in kwargs: + arg_val = kwargs.pop(arg_name) + self.__setattr__(arg_name, arg_val) + else: + self.__setattr__(arg_name, deepcopy(PARAMETERS[arg_name]["default"])) + + if kwargs: + key, _ = kwargs.popitem() + raise AttributeError(f"BertiniConfig has no attribute '{key}'") + + self._validate() + + def __str__(self): + s = "CONFIG\n" + for key, val in PARAMETERS.items(): + instance_val = self.__getattribute__(key) + if instance_val != val["default"]: + s += f"{key}:{instance_val};\n" + s += "END;" + return s + + def _validate(self): + """Ensure combinations of parameters play nicely.""" + if self.mptype != 1 and self.precision != PARAMETERS["precision"]["default"]: + raise ValueError("you have set a non-default precision but have specified " + f"{'double' if self.mptype == 0 else 'adaptive'} precision") + + def needs_component(self): + return self.tracktype in (self.TSAMPLE, self.TMEMTEST, self.TPRINTWS, + self.TPROJECT, self.TREGENEXT) + + def needs_start_points(self): + nsp = self.tracktype in (self.TEVALP, self.TEVALPJ, self.TNEWTP, self.TNEWTPJ, self.TMEMTEST, + self.TISOSTAB) or self.parameterhomotopy == 2 + return nsp + + def needs_sample_count(self): + return self.tracktype == self.TSAMPLE + + def needs_projection_variables(self): + return self.tracktype == self.TPROJECT + + @property + def ampmaxprec(self): + return self._ampmaxprec + + @ampmaxprec.setter + def ampmaxprec(self, val): + val, is_valid = _validate_param("ampmaxprec", val) + if not is_valid: + raise ValueError("ampmaxprec must be an integer greater than or equal to 64") + self._ampmaxprec = val + + @property + def coeffbound(self): + return self._coeffbound + + @coeffbound.setter + def coeffbound(self, val): + val, is_valid = _validate_param("coeffbound", val) + if not is_valid: + raise ValueError("coeffbound must be a positive double") + self._coeffbound = val + + @property + def degreebound(self): + return self._degreebound + + @degreebound.setter + def degreebound(self, val): + val, is_valid = _validate_param("degreebound", val) + if not is_valid: + raise ValueError("degreebound must be a positive double") + self._degreebound = val + + @property + def finaltol(self): + return self._finaltol + + @finaltol.setter + def finaltol(self, val): + val, is_valid = _validate_param("finaltol", val) + if not is_valid: + raise ValueError("finaltol must be a positive double") + self._finaltol = val + + @property + def imagthreshold(self): + return self._finaltol + + @imagthreshold.setter + def imagthreshold(self, val): + val, is_valid = _validate_param("imagthreshold", val) + if not is_valid: + raise ValueError("imagthreshold must be a positive double") + self._imagthreshold = val + + @property + def mptype(self): + return self._mptype + + @mptype.setter + def mptype(self, val): + val, is_valid = _validate_param("mptype", val) + if not is_valid: + raise ValueError( + f"mptype must take one of the following values: {','.join(map(str, range(0, 3)))}") + self._mptype = val + + @property + def parameterhomotopy(self): + return self._parameterhomotopy + + @parameterhomotopy.setter + def parameterhomotopy(self, val): + val, is_valid = _validate_param("parameterhomotopy", val) + if not is_valid: + raise ValueError( + f"parameterhomotopy must take one of the following values: {','.join(map(str, range(0, 3)))}") + self._parameterhomotopy = val + + @property + def precision(self): + return self._precision + + @precision.setter + def precision(self, val): + val, is_valid = _validate_param("precision", val) + if not is_valid: + raise ValueError("precision must be an integer greater than or equal to 64") + self._precision = val + + @property + def randomseed(self): + return self._randomseed + + @randomseed.setter + def randomseed(self, val): + val, is_valid = _validate_param("randomseed", val) + if not is_valid: + raise ValueError("randomseed must be a nonnegative integer") + self._randomseed = val + + @property + def tracktolbeforeeg(self): + return self._tracktolbeforeeg + + @tracktolbeforeeg.setter + def tracktolbeforeeg(self, val): + val, is_valid = _validate_param("tracktolbeforeeg", val) + if not is_valid: + raise ValueError(f"tracktolbeforeeg must be a positive double") + self._tracktolbeforeeg = val + + @property + def tracktype(self): + return self._tracktype + + @tracktype.setter + def tracktype(self, val): + val, is_valid = _validate_param("tracktype", val) + if not is_valid: + raise ValueError(f"tracktype must take one of the following values: {','.join(map(str, range(-4, 7)))}") + self._tracktype = int(val) diff --git a/bertini/io/input_file.py b/bertini/io/input_file/input_section.py similarity index 65% rename from bertini/io/input_file.py rename to bertini/io/input_file/input_section.py index 776d452..3e58777 100644 --- a/bertini/io/input_file.py +++ b/bertini/io/input_file/input_section.py @@ -23,6 +23,8 @@ def _ordereddict_of_type(obj, dtype): PARAMETERS = OrderedDict(tracktype={"default": 0, "is valid": lambda x: x in range(-4, 8)}, + tracktolbeforeeg={"default": 1e-11, + "is valid": lambda x: isinstance(x, Number) and x > 0}, mptype={"default": 2, "is valid": lambda x: x in range(0, 3)}, precision={"default": 96, @@ -80,178 +82,6 @@ def _validate_param(name, val): "is valid": lambda x: _ordereddict_of_type(x, str)}) -class BertiniConfig(object): - TEVALP = -4 - TEVALPJ = -3 - TNEWTP = -2 - TNEWTPJ = -1 - TZERODIM = 0 # parallel - TPOSDIM = 1 # parallel - TSAMPLE = 2 - TMEMTEST = 3 - TPRINTWS = 4 - TPROJECT = 5 - TISOSTAB = 6 - TREGENEXT = 7 # parallel - - def __init__(self, **kwargs): - for arg_name in PARAMETERS: - if arg_name in kwargs: - arg_val = kwargs.pop(arg_name) - self.__setattr__(arg_name, arg_val) - else: - self.__setattr__(arg_name, deepcopy(PARAMETERS[arg_name]["default"])) - - if kwargs: - key, _ = kwargs.popitem() - raise AttributeError(f"BertiniConfig has no attribute '{key}'") - - self._validate() - - def __str__(self): - s = "CONFIG\n" - for key, val in PARAMETERS.items(): - instance_val = self.__getattribute__(key) - if instance_val != val["default"]: - s += f"{key}:{instance_val};\n" - s += "END;" - return s - - def _validate(self): - """Ensure combinations of parameters play nicely.""" - if self.mptype != 1 and self.precision != PARAMETERS["precision"]["default"]: - raise ValueError("you have set a non-default precision but have specified " - f"{'double' if self.mptype == 0 else 'adaptive'} precision") - - def needs_component(self): - return self.tracktype in (self.TSAMPLE, self.TMEMTEST, self.TPRINTWS, - self.TPROJECT, self.TREGENEXT) - - def needs_start_points(self): - nsp = self.tracktype in (self.TEVALP, self.TEVALPJ, self.TNEWTP, self.TNEWTPJ, self.TMEMTEST, - self.TISOSTAB) or self.parameterhomotopy == 2 - return nsp - - def needs_sample_count(self): - return self.tracktype == self.TSAMPLE - - def needs_projection_variables(self): - return self.tracktype == self.TPROJECT - - @property - def ampmaxprec(self): - return self._ampmaxprec - - @ampmaxprec.setter - def ampmaxprec(self, val): - val, is_valid = _validate_param("ampmaxprec", val) - if not is_valid: - raise ValueError("ampmaxprec must be an integer greater than or equal to 64") - self._ampmaxprec = val - - @property - def coeffbound(self): - return self._coeffbound - - @coeffbound.setter - def coeffbound(self, val): - val, is_valid = _validate_param("coeffbound", val) - if not is_valid: - raise ValueError("coeffbound must be a positive double") - self._coeffbound = val - - @property - def degreebound(self): - return self._degreebound - - @degreebound.setter - def degreebound(self, val): - val, is_valid = _validate_param("degreebound", val) - if not is_valid: - raise ValueError("degreebound must be a positive double") - self._degreebound = val - - @property - def finaltol(self): - return self._finaltol - - @finaltol.setter - def finaltol(self, val): - val, is_valid = _validate_param("finaltol", val) - if not is_valid: - raise ValueError("finaltol must be a positive double") - self._finaltol = val - - @property - def imagthreshold(self): - return self._finaltol - - @imagthreshold.setter - def imagthreshold(self, val): - val, is_valid = _validate_param("imagthreshold", val) - if not is_valid: - raise ValueError("imagthreshold must be a positive double") - self._imagthreshold = val - - @property - def mptype(self): - return self._mptype - - @mptype.setter - def mptype(self, val): - val, is_valid = _validate_param("mptype", val) - if not is_valid: - raise ValueError( - f"mptype must take one of the following values: {','.join(map(str, range(0, 3)))}") - self._mptype = val - - - @property - def parameterhomotopy(self): - return self._parameterhomotopy - - @parameterhomotopy.setter - def parameterhomotopy(self, val): - val, is_valid = _validate_param("parameterhomotopy", val) - if not is_valid: - raise ValueError( - f"parameterhomotopy must take one of the following values: {','.join(map(str, range(0, 3)))}") - self._parameterhomotopy = val - - @property - def precision(self): - return self._precision - - @precision.setter - def precision(self, val): - val, is_valid = _validate_param("precision", val) - if not is_valid: - raise ValueError("precision must be an integer greater than or equal to 64") - self._precision = val - - @property - def randomseed(self): - return self._randomseed - - @randomseed.setter - def randomseed(self, val): - val, is_valid = _validate_param("randomseed", val) - if not is_valid: - raise ValueError("randomseed must be a nonnegative integer") - self._randomseed = val - - @property - def tracktype(self): - return self._tracktype - - @tracktype.setter - def tracktype(self, val): - val, is_valid = _validate_param("tracktype", val) - if not is_valid: - raise ValueError(f"tracktype must take one of the following values: {','.join(map(str, range(-4, 7)))}") - self._tracktype = int(val) - - class BertiniInput(object): def __init__(self, **kwargs): for arg_name in INPUT_TYPES: diff --git a/bertini/io/bertini_result.py b/bertini/io/reader.py similarity index 100% rename from bertini/io/bertini_result.py rename to bertini/io/reader.py diff --git a/bertini/io/result.py b/bertini/io/result.py new file mode 100644 index 0000000..6b27057 --- /dev/null +++ b/bertini/io/result.py @@ -0,0 +1,45 @@ +from os import path as op + +from bertini.io.input_file.input_section import BertiniInput +from bertini.io.input_file.config_section import BertiniConfig + + +class BertiniResult: + def __init__(self, dirname, **kwargs): + """The output of a Bertini run. + + Parameters + ---------- + dirname : str + Path to directory where run was done. + kwargs + """ + self._dirname = dirname + + @property + def config(self): + """Configuration needed to reproduce the run.""" + return self._config + + @config.setter + def config(self, val): + assert isinstance(val, BertiniConfig) + self._config = val + + @property + def dirname(self): + return self._dirname + @dirname.setter + def dirname(self, val): + assert op.isdir(val) + self._dirname = val + + @property + def inputs(self): + """Inputs needed to reproduce the run.""" + return self._inputs + + @inputs.setter + def inputs(self, val): + assert isinstance(val, BertiniInput) + self._inputs = val \ No newline at end of file diff --git a/bertini/io/io.py b/bertini/io/utils.py similarity index 95% rename from bertini/io/io.py rename to bertini/io/utils.py index c6d87e8..4a463b8 100644 --- a/bertini/io/io.py +++ b/bertini/io/utils.py @@ -10,49 +10,10 @@ import mpmath as mp import numpy as np -from bertini.io.input_file import BertiniConfig, BertiniInput +from bertini.io.input_file.input_section import BertiniInput +from bertini.io.input_file.config_section import BertiniConfig from bertini.exceptions import UnclassifiedException - - -class BertiniResult: - def __init__(self, dirname, **kwargs): - """The output of a Bertini run. - - Parameters - ---------- - dirname : str - Path to directory where run was done. - kwargs - """ - self._dirname = dirname - - @property - def config(self): - """Configuration needed to reproduce the run.""" - return self._config - - @config.setter - def config(self, val): - assert isinstance(val, BertiniConfig) - self._config = val - - @property - def dirname(self): - return self._dirname - @dirname.setter - def dirname(self, val): - assert op.isdir(val) - self._dirname = val - - @property - def inputs(self): - """Inputs needed to reproduce the run.""" - return self._inputs - - @inputs.setter - def inputs(self, val): - assert isinstance(val, BertiniInput) - self._inputs = val +from bertini.io.result import BertiniResult def _line_to_complex(line: str, multi: bool = False) -> complex: diff --git a/bertini/run.py b/bertini/run.py index d834891..cb16057 100644 --- a/bertini/run.py +++ b/bertini/run.py @@ -9,9 +9,9 @@ from typing import Union -from bertini.io.input_file import BertiniConfig, BertiniInput -from bertini.io.io import (read_input_file, read_main_data_file, read_points_file, read_witness_data_file, - write_input_file, write_points_file, extract_error_message) +from bertini.io.input_file import BertiniInput, BertiniConfig +from bertini.io.utils import (read_main_data_file, read_points_file, write_input_file, write_points_file, + extract_error_message) from bertini.exceptions import BertiniError @@ -92,7 +92,6 @@ def __init__(self, config, inputs, **kwargs): else: raise ValueError("you have selected parameterhomotopy:2 but you have not given final parameters") - if "bertini_path" in kwargs: if not op.isfile(kwargs["bertini_path"]): raise OSError(f"didn't find Bertini at '{kwargs['bertini_path']}'") @@ -165,12 +164,12 @@ def _recover_input(self): except ValueError: msg = 'no main_data file!' raise BertiniError(msg) - inlines = lines[dex+1:] + inlines = lines[dex + 1:] while inlines[0] == '\n': inlines = inlines[1:] dex = inlines.index('END;\n') - inlines = inlines[:dex+1] + inlines = inlines[:dex + 1] return inlines @@ -262,9 +261,9 @@ def run(self, dirname: str = None, tee: bool = True): """ # in case the user has changed any of these - if self._parallel and self._mpi is not None: + if self._parallel and self._mpi is not None and multiprocessing.cpu_count() >= 2: cmd = self._mpi - arg = [cmd, '-np', str(multiprocessing.cpu_count()), self._bertini, "input"] + arg = [cmd, '-np', str(multiprocessing.cpu_count() // 2), self._bertini, "input"] else: arg = [self._bertini, "input"] @@ -325,8 +324,10 @@ def setup(self, dirname: str = None): write_input_file(self.config, self.inputs, input_file) if self.config.parameterhomotopy == 2: - write_points_file(self.start_parameters.reshape(1, self.start_parameters.size), op.join(self._dirname, "start_parameters")) - write_points_file(self.final_parameters.reshape(1, self.final_parameters.size), op.join(self._dirname, "final_parameters")) + write_points_file(self.start_parameters.reshape(1, self.start_parameters.size), + op.join(self._dirname, "start_parameters")) + write_points_file(self.final_parameters.reshape(1, self.final_parameters.size), + op.join(self._dirname, "final_parameters")) write_points_file(self.start, op.join(self._dirname, "start")) @property diff --git a/environment.yml b/environment.yml index 8f95ac6..6675e08 100644 --- a/environment.yml +++ b/environment.yml @@ -1,8 +1,9 @@ -name: bertini +name: python-bertini channels: - defaults - conda-forge dependencies: - python=3.* - numpy +- scipy - mpmath \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index cdde399..5d17483 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ mpmath numpy -pytest \ No newline at end of file +pytest +scipy diff --git a/test/context.py b/test/conftest.py similarity index 100% rename from test/context.py rename to test/conftest.py diff --git a/test/test_input_file.py b/test/test_input_file.py index 476e3d8..1805ea6 100644 --- a/test/test_input_file.py +++ b/test/test_input_file.py @@ -1,8 +1,6 @@ -from context import op, BASEDIR - from collections import OrderedDict -from bertini.io.input_file import BertiniInput, BertiniConfig +from bertini.io.input_file.input_section import BertiniInput def test_inputs_parameter_homotopy(): diff --git a/test/test_io.py b/test/test_io.py index 2cfef5b..011951f 100644 --- a/test/test_io.py +++ b/test/test_io.py @@ -1,7 +1,8 @@ -from context import op, ZERO_DIM_BASE, POS_DIM_BASE +from conftest import op, ZERO_DIM_BASE, POS_DIM_BASE -from bertini.io.io import read_input_file -from bertini.io.input_file import BertiniInput, BertiniConfig +from bertini.io.utils import read_input_file +from bertini.io.input_file.input_section import BertiniInput +from bertini.io.input_file.config_section import BertiniConfig def is_empty(x): diff --git a/test/test_parameter_homotopy.py b/test/test_parameter_homotopy.py index cbead45..bffc408 100644 --- a/test/test_parameter_homotopy.py +++ b/test/test_parameter_homotopy.py @@ -1,12 +1,13 @@ -from context import op, ZERO_DIM_BASE +from conftest import op, ZERO_DIM_BASE from collections import OrderedDict import numpy as np -from bertini.io.io import write_input_file +from bertini.io.utils import write_input_file from bertini.run import BertiniRun -from bertini.io.input_file import BertiniInput, BertiniConfig +from bertini.io.input_file.input_section import BertiniInput +from bertini.io.input_file.config_section import BertiniConfig class TestParameterHomotopy: From 9a20dfeeb0d1d04fd70092ca6aa2a34e1ae6d851 Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Wed, 31 Mar 2021 10:53:19 -0400 Subject: [PATCH 25/25] update installation instructions --- README.md | 24 +++++++++++++++--------- setup.py | 8 ++++---- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index e173565..58114f4 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,25 @@ -# NAGlib +# python-bertini -NAGlib is a Python library for numerical algebraic geometry. +python-bertini is a Python library for numerical algebraic geometry. Mostly, it's just a wrapper around [Bertini](https://bertini.nd.edu) (sold separately). -(Note: I am not a member of Bertini team, just an interested user who likes automating things.) -## Installing NAGlib +## Installing python-bertini -Don't install NAGlib. +Don't install python-bertini. It's not ready yet. -If you want something right now and you're into Julia, you might try [Bertini.jl](https://github.com/PBrdng/Bertini.jl). +If you want something right now, and you're into Julia, you might try [Bertini.jl](https://github.com/PBrdng/Bertini.jl). -If you absolutely must, ensure you have Python 3, NumPy, and [mpmath](https://mpmath.readthedocs.io/en/latest/), then run +If you absolutely must, then clone this repository, cd to the base directory, and run either ```shell -$ python setup.py develop +$ conda env create -n bertini -f environment.yml # if you have anaconda +``` +or (with your virtualenv activated) +```shell +$ pip install -U -r requirements.txt # if you just want to use a virtualenv ``` -in this directory. \ No newline at end of file +Then in either case run +```shell +$ pip install -e . +``` \ No newline at end of file diff --git a/setup.py b/setup.py index 78a6998..c419344 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,12 @@ from setuptools import setup setup( - name='io', + name='bertini', version='0.1.0', - packages=['io', 'io.io'], - url='https://github.com/aliddell/naglib', + packages=['bertini'], + url='https://github.com/aliddell/python-bertini', license='BSD', author='Alan', - author_email='alan @t liddells d.t org', + author_email='alan d.t c d.t liddell @t gmail d.t com', description='Library for numerical algebraic geometry, mostly a wrapper for Bertini classic' )