Coverage for sympy/polys/polyoptions.py : 22%
        
        
    Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
| 
 """Options manager for :class:`Poly` and public API functions. """ 
 from __future__ import print_function, division 
 __all__ = ["Options"] 
 from sympy.core import S, Basic, sympify from sympy.core.compatibility import string_types, with_metaclass from sympy.utilities import numbered_symbols, topological_sort, public from sympy.utilities.iterables import has_dups from sympy.polys.polyerrors import GeneratorsError, OptionError, FlagError 
 import sympy.polys 
 import re 
 class Option(object): """Base class for all kinds of options. """ 
 option = None 
 is_Flag = False 
 requires = [] excludes = [] 
 after = [] before = [] 
 @classmethod def default(cls): 
 @classmethod def preprocess(cls, option): return None 
 @classmethod def postprocess(cls, options): 
 
 class Flag(Option): """Base class for all kinds of flags. """ 
 is_Flag = True 
 
 class BooleanOption(Option): """An option that must have a boolean value or equivalent assigned. """ 
 @classmethod def preprocess(cls, value): else: raise OptionError("'%s' must have a boolean value assigned, got %s" % (cls.option, value)) 
 
 class OptionType(type): """Base type for all options that does registers options. """ 
 def __init__(cls, *args, **kwargs): @property def getter(self): 
 setattr(Options, cls.option, getter) Options.__options__[cls.option] = cls 
 
 @public class Options(dict): """ Options manager for polynomial manipulation module. 
 Examples ======== 
 >>> from sympy.polys.polyoptions import Options >>> from sympy.polys.polyoptions import build_options 
 >>> from sympy.abc import x, y, z 
 >>> Options((x, y, z), {'domain': 'ZZ'}) {'auto': False, 'domain': ZZ, 'gens': (x, y, z)} 
 >>> build_options((x, y, z), {'domain': 'ZZ'}) {'auto': False, 'domain': ZZ, 'gens': (x, y, z)} 
 **Options** 
 * Expand --- boolean option * Gens --- option * Wrt --- option * Sort --- option * Order --- option * Field --- boolean option * Greedy --- boolean option * Domain --- option * Split --- boolean option * Gaussian --- boolean option * Extension --- option * Modulus --- option * Symmetric --- boolean option * Strict --- boolean option 
 **Flags** 
 * Auto --- boolean flag * Frac --- boolean flag * Formal --- boolean flag * Polys --- boolean flag * Include --- boolean flag * All --- boolean flag * Gen --- flag * Series --- boolean flag 
 """ 
 __order__ = None __options__ = {} 
 def __init__(self, gens, args, flags=None, strict=False): 
 raise OptionError( "both '*gens' and keyword argument 'gens' supplied") 
 
 except KeyError: raise OptionError("'%s' is not a valid option" % option) 
 raise OptionError("'%s' flag is not allowed in this context" % option) 
 
 
 if key in self: del defaults[key] else: for option in self.keys(): cls = self.__options__[option] 
 if key in cls.excludes: del defaults[key] break 
 
 
 if self.get(require_option) is None: raise OptionError("'%s' option is only allowed together with '%s'" % (option, require_option)) 
 raise OptionError("'%s' option is not allowed together with '%s'" % (option, exclude_option)) 
 
 @classmethod def _init_dependencies_order(cls): """Resolve the order of options' processing. """ if cls.__order__ is None: vertices, edges = [], set([]) 
 for name, option in cls.__options__.items(): vertices.append(name) 
 for _name in option.after: edges.add((_name, name)) 
 for _name in option.before: edges.add((name, _name)) 
 try: cls.__order__ = topological_sort((vertices, list(edges))) except ValueError: raise RuntimeError( "cycle detected in sympy.polys options framework") 
 def clone(self, updates={}): """Clone ``self`` and update specified options. """ 
 
 
 
 def __setattr__(self, attr, value): else: super(Options, self).__setattr__(attr, value) 
 @property def args(self): args = {} 
 for option, value in self.items(): if value is not None and option != 'gens': cls = self.__options__[option] 
 if not issubclass(cls, Flag): args[option] = value 
 return args 
 @property def options(self): options = {} 
 for option, cls in self.__options__.items(): if not issubclass(cls, Flag): options[option] = getattr(self, option) 
 return options 
 @property def flags(self): flags = {} 
 for option, cls in self.__options__.items(): if issubclass(cls, Flag): flags[option] = getattr(self, option) 
 return flags 
 
 class Expand(with_metaclass(OptionType, BooleanOption)): """``expand`` option to polynomial manipulation functions. """ 
 option = 'expand' 
 requires = [] excludes = [] 
 @classmethod def default(cls): 
 
 class Gens(with_metaclass(OptionType, Option)): """``gens`` option to polynomial manipulation functions. """ 
 option = 'gens' 
 requires = [] excludes = [] 
 @classmethod def default(cls): 
 @classmethod def preprocess(cls, gens): gens = (gens,) 
 raise GeneratorsError("duplicated generators: %s" % str(gens)) raise GeneratorsError("non-commutative generators: %s" % str(gens)) 
 
 
 class Wrt(with_metaclass(OptionType, Option)): """``wrt`` option to polynomial manipulation functions. """ 
 option = 'wrt' 
 requires = [] excludes = [] 
 _re_split = re.compile(r"\s*,\s*|\s+") 
 @classmethod def preprocess(cls, wrt): if isinstance(wrt, Basic): return [str(wrt)] elif isinstance(wrt, str): wrt = wrt.strip() if wrt.endswith(','): raise OptionError('Bad input: missing parameter.') if not wrt: return [] return [ gen for gen in cls._re_split.split(wrt) ] elif hasattr(wrt, '__getitem__'): return list(map(str, wrt)) else: raise OptionError("invalid argument for 'wrt' option") 
 
 class Sort(with_metaclass(OptionType, Option)): """``sort`` option to polynomial manipulation functions. """ 
 option = 'sort' 
 requires = [] excludes = [] 
 @classmethod def default(cls): 
 @classmethod def preprocess(cls, sort): if isinstance(sort, str): return [ gen.strip() for gen in sort.split('>') ] elif hasattr(sort, '__getitem__'): return list(map(str, sort)) else: raise OptionError("invalid argument for 'sort' option") 
 
 class Order(with_metaclass(OptionType, Option)): """``order`` option to polynomial manipulation functions. """ 
 option = 'order' 
 requires = [] excludes = [] 
 @classmethod def default(cls): 
 @classmethod def preprocess(cls, order): 
 
 class Field(with_metaclass(OptionType, BooleanOption)): """``field`` option to polynomial manipulation functions. """ 
 option = 'field' 
 requires = [] excludes = ['domain', 'split', 'gaussian'] 
 
 class Greedy(with_metaclass(OptionType, BooleanOption)): """``greedy`` option to polynomial manipulation functions. """ 
 option = 'greedy' 
 requires = [] excludes = ['domain', 'split', 'gaussian', 'extension', 'modulus', 'symmetric'] 
 
 class Composite(with_metaclass(OptionType, BooleanOption)): """``composite`` option to polynomial manipulation functions. """ 
 option = 'composite' 
 @classmethod def default(cls): 
 requires = [] excludes = ['domain', 'split', 'gaussian', 'extension', 'modulus', 'symmetric'] 
 
 class Domain(with_metaclass(OptionType, Option)): """``domain`` option to polynomial manipulation functions. """ 
 option = 'domain' 
 requires = [] excludes = ['field', 'greedy', 'split', 'gaussian', 'extension'] 
 after = ['gens'] 
 _re_realfield = re.compile("^(R|RR)(_(\d+))?$") _re_complexfield = re.compile("^(C|CC)(_(\d+))?$") _re_finitefield = re.compile("^(FF|GF)\((\d+)\)$") _re_polynomial = re.compile("^(Z|ZZ|Q|QQ)\[(.+)\]$") _re_fraction = re.compile("^(Z|ZZ|Q|QQ)\((.+)\)$") _re_algebraic = re.compile("^(Q|QQ)\<(.+)\>$") 
 @classmethod def preprocess(cls, domain): return domain.to_domain() 
 return sympy.polys.domains.QQ 
 
 r = cls._re_realfield.match(domain) 
 if r is not None: _, _, prec = r.groups() 
 if prec is None: return sympy.polys.domains.RR else: return sympy.polys.domains.RealField(int(prec)) 
 r = cls._re_complexfield.match(domain) 
 if r is not None: _, _, prec = r.groups() 
 if prec is None: return sympy.polys.domains.CC else: return sympy.polys.domains.ComplexField(int(prec)) 
 r = cls._re_finitefield.match(domain) 
 if r is not None: return sympy.polys.domains.FF(int(r.groups()[1])) 
 r = cls._re_polynomial.match(domain) 
 if r is not None: ground, gens = r.groups() 
 gens = list(map(sympify, gens.split(','))) 
 if ground in ['Z', 'ZZ']: return sympy.polys.domains.ZZ.poly_ring(*gens) else: return sympy.polys.domains.QQ.poly_ring(*gens) 
 r = cls._re_fraction.match(domain) 
 if r is not None: ground, gens = r.groups() 
 gens = list(map(sympify, gens.split(','))) 
 if ground in ['Z', 'ZZ']: return sympy.polys.domains.ZZ.frac_field(*gens) else: return sympy.polys.domains.QQ.frac_field(*gens) 
 r = cls._re_algebraic.match(domain) 
 if r is not None: gens = list(map(sympify, r.groups()[1].split(','))) return sympy.polys.domains.QQ.algebraic_field(*gens) 
 raise OptionError('expected a valid domain specification, got %s' % domain) 
 @classmethod def postprocess(cls, options): (set(options['domain'].symbols) & set(options['gens'])): raise GeneratorsError( "ground domain and generators interfere together") 'domain' in options and options['domain'] == sympy.polys.domains.EX: raise GeneratorsError("you have to provide generators because EX domain was requested") 
 
 class Split(with_metaclass(OptionType, BooleanOption)): """``split`` option to polynomial manipulation functions. """ 
 option = 'split' 
 requires = [] excludes = ['field', 'greedy', 'domain', 'gaussian', 'extension', 'modulus', 'symmetric'] 
 @classmethod def postprocess(cls, options): raise NotImplementedError("'split' option is not implemented yet") 
 
 class Gaussian(with_metaclass(OptionType, BooleanOption)): """``gaussian`` option to polynomial manipulation functions. """ 
 option = 'gaussian' 
 requires = [] excludes = ['field', 'greedy', 'domain', 'split', 'extension', 'modulus', 'symmetric'] 
 @classmethod def postprocess(cls, options): options['extension'] = set([S.ImaginaryUnit]) Extension.postprocess(options) 
 
 class Extension(with_metaclass(OptionType, Option)): """``extension`` option to polynomial manipulation functions. """ 
 option = 'extension' 
 requires = [] excludes = ['greedy', 'domain', 'split', 'gaussian', 'modulus', 'symmetric'] 
 @classmethod def preprocess(cls, extension): elif extension == 0: raise OptionError("'False' is an invalid argument for 'extension'") else: if not hasattr(extension, '__iter__'): extension = set([extension]) else: if not extension: extension = None else: extension = set(extension) 
 return extension 
 @classmethod def postprocess(cls, options): options['domain'] = sympy.polys.domains.QQ.algebraic_field( *options['extension']) 
 
 class Modulus(with_metaclass(OptionType, Option)): """``modulus`` option to polynomial manipulation functions. """ 
 option = 'modulus' 
 requires = [] excludes = ['greedy', 'split', 'domain', 'gaussian', 'extension'] 
 @classmethod def preprocess(cls, modulus): modulus = sympify(modulus) 
 if modulus.is_Integer and modulus > 0: return int(modulus) else: raise OptionError( "'modulus' must a positive integer, got %s" % modulus) 
 @classmethod def postprocess(cls, options): modulus = options['modulus'] symmetric = options.get('symmetric', True) options['domain'] = sympy.polys.domains.FF(modulus, symmetric) 
 
 class Symmetric(with_metaclass(OptionType, BooleanOption)): """``symmetric`` option to polynomial manipulation functions. """ 
 option = 'symmetric' 
 requires = ['modulus'] excludes = ['greedy', 'domain', 'split', 'gaussian', 'extension'] 
 
 class Strict(with_metaclass(OptionType, BooleanOption)): """``strict`` option to polynomial manipulation functions. """ 
 option = 'strict' 
 @classmethod def default(cls): return True 
 
 class Auto(with_metaclass(OptionType, BooleanOption, Flag)): """``auto`` flag to polynomial manipulation functions. """ 
 option = 'auto' 
 after = ['field', 'domain', 'extension', 'gaussian'] 
 @classmethod def default(cls): return True 
 @classmethod def postprocess(cls, options): 
 
 class Frac(with_metaclass(OptionType, BooleanOption, Flag)): """``auto`` option to polynomial manipulation functions. """ 
 option = 'frac' 
 @classmethod def default(cls): 
 
 class Formal(with_metaclass(OptionType, BooleanOption, Flag)): """``formal`` flag to polynomial manipulation functions. """ 
 option = 'formal' 
 @classmethod def default(cls): return False 
 
 class Polys(with_metaclass(OptionType, BooleanOption, Flag)): """``polys`` flag to polynomial manipulation functions. """ 
 option = 'polys' 
 
 class Include(with_metaclass(OptionType, BooleanOption, Flag)): """``include`` flag to polynomial manipulation functions. """ 
 option = 'include' 
 @classmethod def default(cls): return False 
 
 class All(with_metaclass(OptionType, BooleanOption, Flag)): """``all`` flag to polynomial manipulation functions. """ 
 option = 'all' 
 @classmethod def default(cls): return False 
 
 class Gen(with_metaclass(OptionType, Flag)): """``gen`` flag to polynomial manipulation functions. """ 
 option = 'gen' 
 @classmethod def default(cls): 
 @classmethod def preprocess(cls, gen): if isinstance(gen, (Basic, int)): return gen else: raise OptionError("invalid argument for 'gen' option") 
 
 class Series(with_metaclass(OptionType, BooleanOption, Flag)): """``series`` flag to polynomial manipulation functions. """ 
 option = 'series' 
 @classmethod def default(cls): 
 
 class Symbols(with_metaclass(OptionType, Flag)): """``symbols`` flag to polynomial manipulation functions. """ 
 option = 'symbols' 
 @classmethod def default(cls): return numbered_symbols('s', start=1) 
 @classmethod def preprocess(cls, symbols): if hasattr(symbols, '__iter__'): return iter(symbols) else: raise OptionError("expected an iterator or iterable container, got %s" % symbols) 
 
 class Method(with_metaclass(OptionType, Flag)): """``method`` flag to polynomial manipulation functions. """ 
 option = 'method' 
 @classmethod def preprocess(cls, method): if isinstance(method, str): return method.lower() else: raise OptionError("expected a string, got %s" % method) 
 
 def build_options(gens, args=None): """Construct options from keyword arguments or ... options. """ 
 else: 
 
 def allowed_flags(args, flags): """ Allow specified flags to be used in the given context. 
 Examples ======== 
 >>> from sympy.polys.polyoptions import allowed_flags >>> from sympy.polys.domains import ZZ 
 >>> allowed_flags({'domain': ZZ}, []) 
 >>> allowed_flags({'domain': ZZ, 'frac': True}, []) Traceback (most recent call last): ... FlagError: 'frac' flag is not allowed in this context 
 >>> allowed_flags({'domain': ZZ, 'frac': True}, ['frac']) 
 """ 
 raise FlagError( "'%s' flag is not allowed in this context" % arg) except KeyError: raise OptionError("'%s' is not a valid option" % arg) 
 
 def set_defaults(options, **defaults): """Update options with default values. """ if 'defaults' not in options: options = dict(options) options['defaults'] = defaults 
 return options 
 Options._init_dependencies_order()  |