"""
Actual functions to use in Sage
ST 2012-11-13

Command line syntax:
  use from Sage (via the "load" or the "attach" commands)

pobyso functions come in five flavors: 
- the _so_so (arguments and returned objects are pointers to Sollya objects, includes
  the void function and the no arguments function that return a pointer to a Sollya
  object);
- the _so_sa (argument are pointers to Sollya objects, returned objects are
  Sage/Python objects or, more generally, information is transfered from the Sollya
  world to Sage/Python world);
- the _sa_so (arguments are Sage/Python objects, returned objects are 
  pointers to Sollya objects);
- the sa_sa (arguments and returned objects are all Sage/Python objects);
- a catch all flavor, without any suffix, (e. g. functions that have no argument 
  nor return value).
NOTES:
Reported errors in Eclipse come from the calls to
the Sollya library

ToDo (among other things): 
 -memory management.
"""
from ctypes import *
import re
from sage.symbolic.expression_conversions import polynomial
"""
Create the equivalent to an enum for the Sollya function types.
"""
(SOLLYA_BASE_FUNC_ABS,
SOLLYA_BASE_FUNC_ACOS,
    SOLLYA_BASE_FUNC_ACOSH,
    SOLLYA_BASE_FUNC_ADD,
    SOLLYA_BASE_FUNC_ASIN,
    SOLLYA_BASE_FUNC_ASINH,
    SOLLYA_BASE_FUNC_ATAN,
    SOLLYA_BASE_FUNC_ATANH,
    SOLLYA_BASE_FUNC_CEIL,
    SOLLYA_BASE_FUNC_CONSTANT,
    SOLLYA_BASE_FUNC_COS,
    SOLLYA_BASE_FUNC_COSH,
    SOLLYA_BASE_FUNC_DIV,
    SOLLYA_BASE_FUNC_DOUBLE,
    SOLLYA_BASE_FUNC_DOUBLEDOUBLE,
    SOLLYA_BASE_FUNC_DOUBLEEXTENDED,
    SOLLYA_BASE_FUNC_ERF,
    SOLLYA_BASE_FUNC_ERFC,
    SOLLYA_BASE_FUNC_EXP,
    SOLLYA_BASE_FUNC_EXP_M1,
    SOLLYA_BASE_FUNC_FLOOR,
    SOLLYA_BASE_FUNC_FREE_VARIABLE,
    SOLLYA_BASE_FUNC_HALFPRECISION,
    SOLLYA_BASE_FUNC_LIBRARYCONSTANT,
    SOLLYA_BASE_FUNC_LIBRARYFUNCTION,
    SOLLYA_BASE_FUNC_LOG,
    SOLLYA_BASE_FUNC_LOG_10,
    SOLLYA_BASE_FUNC_LOG_1P,
    SOLLYA_BASE_FUNC_LOG_2,
    SOLLYA_BASE_FUNC_MUL,
    SOLLYA_BASE_FUNC_NEARESTINT,
    SOLLYA_BASE_FUNC_NEG,
    SOLLYA_BASE_FUNC_PI,
    SOLLYA_BASE_FUNC_POW,
    SOLLYA_BASE_FUNC_PROCEDUREFUNCTION,
    SOLLYA_BASE_FUNC_QUAD,
    SOLLYA_BASE_FUNC_SIN,
    SOLLYA_BASE_FUNC_SINGLE,
    SOLLYA_BASE_FUNC_SINH,
    SOLLYA_BASE_FUNC_SQRT,
    SOLLYA_BASE_FUNC_SUB,
    SOLLYA_BASE_FUNC_TAN,
    SOLLYA_BASE_FUNC_TANH,
SOLLYA_BASE_FUNC_TRIPLEDOUBLE) = map(int,xrange(44))
print "First constant - SOLLYA_BASE_FUNC_ABS: ", SOLLYA_BASE_FUNC_ABS
print "Last constant  - SOLLYA_BASE_FUNC_TRIPLEDOUBLE: ", SOLLYA_BASE_FUNC_TRIPLEDOUBLE

pobyso_max_arity = 9

def pobyso_autoprint(arg):
    sollya_lib_autoprint(arg,None)

def pobyso_autoprint_so_so(arg):
    sollya_lib_autoprint(arg,None)
    
def pobyso_absolute_so_so():
    return(sollya_lib_absolute(None))

def pobyso_build_function_sub_so_so(exp1So, exp2So):
    return(sollya_lib_build_function_sub(exp1So, exp2So))

def pobyso_cmp(rnArg, soCte):
    """
    Compare the MPFR value a RealNumber with that of a Sollya constant.
    
    Get the value of the Sollya constant into a RealNumber and compare
    using MPFR. Could be optimized by working directly with a mpfr_t
    for the intermediate number. 
    """
    precisionOfCte = c_int(0)
    # From the Sollya constant, create a local Sage RealNumber.
    sollya_lib_get_prec_of_constant(precisionOfCte, soCte) 
    #print "Precision of constant: ", precisionOfCte
    RRRR = RealField(precisionOfCte.value)
    rnLocal = RRRR(0)
    sollya_lib_get_constant(get_rn_value(rnLocal), soCte)
    #print "rnDummy: ", rnDummy
    # Compare the local Sage RealNumber with rnArg.
    return(cmp_rn_value(rnArg, rnLocal))

def pobyso_change_var_in_function_so_so(funcSo, chvarExpSo):
    return(sollya_lib_evaluate(funcSo,chvarExpSo))
    

def pobyso_chebyshevform_so_so(functionSo, degreeSo, intervalSo):
    resultSo = sollya_lib_chebyshevform(functionSo, degreeSo, intervalSo)
    return(resultSo)
        


def pobyso_compute_pos_function_abs_val_bounds_sa_sa(funcSa, lowerBoundSa, \
                                                     upperBoundSa):
    """
    TODO: set the variable name in Sollya.
    """
    funcSo = pobyso_parse_string(funcSa._assume_str())
    rangeSo = pobyso_range_sa_so(lowerBoundSa, upperBoundSa)
    infnormSo = pobyso_infnorm_so_so(funcSo,rangeSo)
    fMaxSa = pobyso_get_interval_from_range_so_sa(infnormSo)
    # Get the top bound and compute the binade top limit.
    fMaxUpperBoundSa = fMaxSa.upper()
    binadeTopLimitSa = 2**ceil(fMaxUpperBoundSa.log2())
    # Put up together the function to use to compute the lower bound.
    funcAuxSo = pobyso_parse_string(str(binadeTopLimitSa) +  \
                                    '-(' + f._assume_str() + ')')
    pobyso_autoprint(funcAuxSo)
    # Clear the Sollay range before a new call to infnorm and issue the call.
    sollya_lib_clear_obj(infnormSo)
    infnormSo = pobyso_infnorm_so_so(funcAuxSo,rangeSo)
    fMinSa = pobyso_get_interval_from_range_so_sa(infnormSo)
    sollya_lib_clear_obj(infnormSo)
    fMinLowerBoundSa = topBinadeLimit - fMinSa.lower()
    # Compute the maximum of the precisions of the different bounds.
    maxPrecSa = max([fMinLowerBoundSa.parent().precision(), \
                     fMaxUpperBoundSa.parent().precision()])
    # Create a RealIntervalField and create an interval with the "good" bounds.
    RRRI = RealIntervalField(maxPrecSa)
    imageIntervalSa = RRRI(fMinLowerBoundSa, fMaxUpperBoundSa)
    # Free the uneeded Sollya objects
    sollya_lib_clear_obj(funcSo)
    sollya_lib_clear_obj(funcAuxSo)
    sollya_lib_clear_obj(rangeSo)
    return(imageIntervalSa)
    # End pobyso_compute_function_abs_val_bounds_sa_sa

def pobyso_constant(rnArg):
    """ Legacy function. See pobyso_constant_sa_so. """
    return(pobyso_constant_sa_so(rnArg))
    
def pobyso_constant_sa_so(rnArg):
    """
    Create a Sollya constant from a RealNumber.
    """
    return(sollya_lib_constant(get_rn_value(rnArg)))
    
def pobyso_constant_0_sa_so():
    return(pobyso_constant_from_int_sa_so(0))

def pobyso_constant_1():
    """ Legacy function. See pobyso_constant_so_so. """
    return(pobyso_constant_1_sa_so())

def pobyso_constant_1_sa_so():
    return(pobyso_constant_from_int_sa_so(1))

def pobyso_constant_from_int(anInt):
    """ Legacy function. See pobyso_constant_from_int_sa_so. """
    return(pobyso_constant_from_int_sa_so(anInt))

def pobyso_constant_from_int_sa_so(anInt):
    return(sollya_lib_constant_from_int(int(anInt)))

def pobyso_function_type_as_string(funcType):
    """ Legacy function. See pobyso_function_type_as_string_so_sa. """
    return(pobyso_function_type_as_string_so_sa(funcType))

def pobyso_function_type_as_string_so_sa(funcType):
    """
    Numeric Sollya function codes -> Sage mathematical function names.
    Notice that pow -> ^ (a la Sage, not a la Python).
    """
    if funcType == SOLLYA_BASE_FUNC_ABS:
        return "abs"
    elif funcType == SOLLYA_BASE_FUNC_ACOS:
        return "arccos"
    elif funcType == SOLLYA_BASE_FUNC_ACOSH:
        return "arccosh"
    elif funcType == SOLLYA_BASE_FUNC_ADD:
        return "+"
    elif funcType == SOLLYA_BASE_FUNC_ASIN:
        return "arcsin"
    elif funcType == SOLLYA_BASE_FUNC_ASINH:
        return "arcsinh"
    elif funcType == SOLLYA_BASE_FUNC_ATAN:
        return "arctan"
    elif funcType == SOLLYA_BASE_FUNC_ATANH:
        return "arctanh"
    elif funcType == SOLLYA_BASE_FUNC_CEIL:
        return "ceil"
    elif funcType == SOLLYA_BASE_FUNC_CONSTANT:
        return "cte"
    elif funcType == SOLLYA_BASE_FUNC_COS:
        return "cos"
    elif funcType == SOLLYA_BASE_FUNC_COSH:
        return "cosh"
    elif funcType == SOLLYA_BASE_FUNC_DIV:
        return "/"
    elif funcType == SOLLYA_BASE_FUNC_DOUBLE:
        return "double"
    elif funcType == SOLLYA_BASE_FUNC_DOUBLEDOUBLE:
        return "doubleDouble"
    elif funcType == SOLLYA_BASE_FUNC_DOUBLEEXTENDED:
        return "doubleDxtended"
    elif funcType == SOLLYA_BASE_FUNC_ERF:
        return "erf"
    elif funcType == SOLLYA_BASE_FUNC_ERFC:
        return "erfc"
    elif funcType == SOLLYA_BASE_FUNC_EXP:
        return "exp"
    elif funcType == SOLLYA_BASE_FUNC_EXP_M1:
        return "expm1"
    elif funcType == SOLLYA_BASE_FUNC_FLOOR:
        return "floor"
    elif funcType == SOLLYA_BASE_FUNC_FREE_VARIABLE:
        return "freeVariable"
    elif funcType == SOLLYA_BASE_FUNC_HALFPRECISION:
        return "halfPrecision"
    elif funcType == SOLLYA_BASE_FUNC_LIBRARYCONSTANT:
        return "libraryConstant"
    elif funcType == SOLLYA_BASE_FUNC_LIBRARYFUNCTION:
        return "libraryFunction"
    elif funcType == SOLLYA_BASE_FUNC_LOG:
        return "log"
    elif funcType == SOLLYA_BASE_FUNC_LOG_10:
        return "log10"
    elif funcType == SOLLYA_BASE_FUNC_LOG_1P:
        return "log1p"
    elif funcType == SOLLYA_BASE_FUNC_LOG_2:
        return "log2"
    elif funcType == SOLLYA_BASE_FUNC_MUL:
        return "*"
    elif funcType == SOLLYA_BASE_FUNC_NEARESTINT:
        return "round"
    elif funcType == SOLLYA_BASE_FUNC_NEG:
        return "__neg__"
    elif funcType == SOLLYA_BASE_FUNC_PI:
        return "pi"
    elif funcType == SOLLYA_BASE_FUNC_POW:
        return "^"
    elif funcType == SOLLYA_BASE_FUNC_PROCEDUREFUNCTION:
        return "procedureFunction"
    elif funcType == SOLLYA_BASE_FUNC_QUAD:
        return "quad"
    elif funcType == SOLLYA_BASE_FUNC_SIN:
        return "sin"
    elif funcType == SOLLYA_BASE_FUNC_SINGLE:
        return "single"
    elif funcType == SOLLYA_BASE_FUNC_SINH:
        return "sinh"
    elif funcType == SOLLYA_BASE_FUNC_SQRT:
        return "sqrt"
    elif funcType == SOLLYA_BASE_FUNC_SUB:
        return "-"
    elif funcType == SOLLYA_BASE_FUNC_TAN:
        return "tan"
    elif funcType == SOLLYA_BASE_FUNC_TANH:
        return "tanh"
    elif funcType == SOLLYA_BASE_FUNC_TRIPLEDOUBLE:
        return "tripleDouble"
    else:
        return None

def pobyso_get_constant(rnArg, soConst):
    """ Legacy function. See pobyso_get_constant_so_sa. """
    return(pobyso_get_constant_so_sa(rnArg, soConst))

def pobyso_get_constant_so_sa(rnArg, soConst):
    """
    Set the value of rnArg to the value of soConst in MPFR_RNDN mode.
    rnArg must already exist and belong to some RealField.
    We assume that soConst points to a Sollya constant.
    """
    return(sollya_lib_get_constant(get_rn_value(rnArg), soConst))
    
def pobyso_get_constant_as_rn(ctExp):
    """ Legacy function. See pobyso_get_constant_as_rn_so_sa. """ 
    return(pobyso_get_constant_as_rn_so_sa(ctExp))
    
def pobyso_get_constant_as_rn_so_sa(constExp):
    precision  = pobyso_get_prec_of_constant(constExp) 
    RRRR = RealField(precision)
    rn = RRRR(0)
    sollya_lib_get_constant(get_rn_value(rn), constExp)
    return(rn)

def pobyso_get_constant_as_rn_with_rf(ctExp, realField):
    """ Legacy function. See pobyso_get_constant_as_rn_with_rf_so_sa."""
    return(pobyso_get_constant_as_rn_with_rf_so_sa(ctExp, realField))
    
def pobyso_get_constant_as_rn_with_rf_so_sa(ctExp, realField):
    rn = realField(0)
    sollya_lib_get_constant(get_rn_value(rn), ctExp)
    return(rn)

def pobyso_get_free_variable_name():
    """ Legacy function. See pobyso_get_free_variable_name_so_sa."""
    return(pobyso_get_free_variable_name_so_sa())

def pobyso_get_free_variable_name_so_sa():
    return(sollya_lib_get_free_variable_name())
    
def pobyso_get_function_arity(expressionSo):
    """ Legacy function. See pobyso_get_function_arity_so_sa."""
    return(pobyso_get_function_arity_so_sa(expressionSo))

def pobyso_get_function_arity_so_sa(expressionSo):
    arity = c_int(0)
    sollya_lib_get_function_arity(byref(arity),expressionSo)
    return(int(arity.value))

def pobyso_get_head_function(expressionSo):
    """ Legacy function. See pobyso_get_head_function_so_sa. """
    return(pobyso_get_head_function_so_sa(expressionSo)) 

def pobyso_get_head_function_so_sa(expressionSo):
    functionType = c_int(0)
    sollya_lib_get_head_function(byref(functionType), expressionSo, None)
    return(int(functionType.value))

def pobyso_get_interval_from_range_so_sa(soRange):
    """
    Return the Sage interval corresponding to the Sollya range argument.
    The interval bounds are not rounded: they are elements of RealIntervalField
    of the "right" precision.
    """
    prec = c_int(0)
    retval = sollya_lib_get_prec_of_range(byref(prec), soRange, None)
    if retval == 0:
        return(None)
    RRRI = RealIntervalField(prec.value)
    intervalSa = RRRI(0,0)
    retval = \
        sollya_lib_get_interval_from_range(get_interval_value(intervalSa),\
                                           soRange)
    if retval == 0:
        return(None)
    return(intervalSa)
    
def pobyso_get_list_elements(soObj):
    """ Legacy function. See pobyso_get_list_elements_so_so. """
    return(pobyso_get_list_elements_so_so(soObj))
 
def pobyso_get_list_elements_so_so(soObj):
    """
    Get the list elements as a Sage/Python array of Sollya objects.
    The other data returned are also Sage/Python objects.
    """
    listAddress = POINTER(c_longlong)()
    numElements = c_int(0)
    isEndElliptic = c_int(0)
    listAsList = []
    result = sollya_lib_get_list_elements(byref(listAddress),\
                                          byref(numElements),\
                                          byref(isEndElliptic),\
                                          soObj)
    if result == 0 :
        return None
    for i in xrange(0, numElements.value, 1):
        listAsList.append(listAddress[i])
    return(listAsList, numElements.value, isEndElliptic.value)

def pobyso_get_max_prec_of_exp(soExp):
    """ Legacy function. See pobyso_get_max_prec_of_exp_so_sa. """
    return(pobyso_get_max_prec_of_exp_so_sa(soExp))

def pobyso_get_max_prec_of_exp_so_sa(soExp):
    """
    Get the maximum precision used for the numbers in a Sollya expression.
    
    Arguments:
    soExp -- a Sollya expression pointer
    Return value:
    A Python integer
    TODO: 
    - error management;
    - correctly deal with numerical type such as DOUBLEEXTENDED.
    """
    maxPrecision = 0
    minConstPrec = 0
    currentConstPrec = 0
    operator = pobyso_get_head_function_so_sa(soExp)
    if (operator != SOLLYA_BASE_FUNC_CONSTANT) and \
    (operator != SOLLYA_BASE_FUNC_FREE_VARIABLE):
        (arity, subexpressions) = pobyso_get_subfunctions_so_sa(soExp)
        for i in xrange(arity):
            maxPrecisionCandidate = \
                pobyso_get_max_prec_of_exp_so_sa(subexpressions[i])
            if maxPrecisionCandidate > maxPrecision:
                maxPrecision = maxPrecisionCandidate
        return(maxPrecision)
    elif operator == SOLLYA_BASE_FUNC_CONSTANT:
        minConstPrec = pobyso_get_min_prec_of_constant_so_sa(soExp)
        #currentConstPrec = pobyso_get_min_prec_of_constant_so_sa(soExp)
        #print minConstPrec, " - ", currentConstPrec 
        return(pobyso_get_min_prec_of_constant_so_sa(soExp))
    
    elif operator == SOLLYA_BASE_FUNC_FREE_VARIABLE:
        return(0)
    else:
        print "pobyso_get_max_prec_of_exp_so_sa: unexepected operator."
        return(0)

def pobyso_get_min_prec_of_constant_so_sa(soConstExp):
    """
    Get the minimum precision necessary to represent the value of a Sollya
    constant.
    MPFR_MIN_PREC and powers of 2 are taken into account.
    We assume that soCteExp is a point
    """
    constExpAsRn = pobyso_get_constant_as_rn_so_sa(soConstExp)
    return(min_mpfr_size(get_rn_value(constExpAsRn)))

def pobyso_get_sage_exp_from_sollya_exp(sollyaExp, realField = RR):
    """ Legacy function. See pobyso_get_sage_exp_from_sollya_exp_so_sa. """
    return(pobyso_get_sage_exp_from_sollya_exp_so_sa(sollyaExp, realField = RR))

def pobyso_get_sage_exp_from_sollya_exp_so_sa(sollyaExp, realField = RR):
    """
    Get a Sage expression from a Sollya expression. 
    Currently only tested with polynomials with floating-point coefficients.
    Notice that, in the returned polynomial, the exponents are RealNumbers.
    """
    #pobyso_autoprint(sollyaExp)
    operator = pobyso_get_head_function_so_sa(sollyaExp)
    # Constants and the free variable are special cases.
    # All other operator are dealt with in the same way.
    if (operator != SOLLYA_BASE_FUNC_CONSTANT) and \
       (operator != SOLLYA_BASE_FUNC_FREE_VARIABLE):
        (arity, subexpressions) = pobyso_get_subfunctions_so_sa(sollyaExp)
        if arity == 1:
            sageExp = eval(pobyso_function_type_as_string_so_sa(operator) + \
            "(" + pobyso_get_sage_exp_from_sollya_exp_so_sa(subexpressions[0], \
            realField) + ")")
        elif arity == 2:
            if operator == SOLLYA_BASE_FUNC_POW:
                operatorAsString = "**"
            else:
                operatorAsString = \
                    pobyso_function_type_as_string_so_sa(operator)
            sageExp = \
              eval("pobyso_get_sage_exp_from_sollya_exp_so_sa(subexpressions[0], realField)"\
              + " " + operatorAsString + " " + \
                   "pobyso_get_sage_exp_from_sollya_exp_so_sa(subexpressions[1], realField)")
        # We do not know yet how to deal with arity > 3 (is there any in Sollya anyway?).
        else:
            sageExp = eval('None')
        return(sageExp)
    elif operator == SOLLYA_BASE_FUNC_CONSTANT:
        #print "This is a constant"
        return pobyso_get_constant_as_rn_with_rf_so_sa(sollyaExp, realField)
    elif operator == SOLLYA_BASE_FUNC_FREE_VARIABLE:
        #print "This is free variable"
        return(eval(sollya_lib_get_free_variable_name()))
    else:
        print "Unexpected"
        return eval('None')
# End pobyso_get_sage_poly_from_sollya_poly
    
def pobyso_get_subfunctions(expressionSo):
    """ Legacy function. See pobyso_get_subfunctions_so_sa. """
    return(pobyso_get_subfunctions_so_sa(expressionSo)) 

def pobyso_get_subfunctions_so_sa(expressionSo):
    """
    Get the subfunctions of an expression.
    Return the number of subfunctions and the list of subfunctions addresses.
    S.T.: Could not figure out another way than that ugly list of declarations
    to recover the addresses of the subfunctions. 
    """
    subf0 = c_int(0)
    subf1 = c_int(0)
    subf2 = c_int(0)
    subf3 = c_int(0)
    subf4 = c_int(0)
    subf5 = c_int(0)
    subf6 = c_int(0)
    subf7 = c_int(0)
    subf8 = c_int(0)
    arity = c_int(0)
    nullPtr = POINTER(c_int)()
    sollya_lib_get_subfunctions(expressionSo, byref(arity), \
    byref(subf0), byref(subf1), byref(subf2), byref(subf3), byref(subf4), byref(subf5),\
     byref(subf6), byref(subf7), byref(subf8), nullPtr, None) 
#    byref(cast(subfunctions[0], POINTER(c_int))), byref(cast(subfunctions[0], POINTER(c_int))), \
#    byref(cast(subfunctions[2], POINTER(c_int))), byref(cast(subfunctions[3], POINTER(c_int))), \
#    byref(cast(subfunctions[4], POINTER(c_int))), byref(cast(subfunctions[5], POINTER(c_int))), \
#    byref(cast(subfunctions[6], POINTER(c_int))), byref(cast(subfunctions[7], POINTER(c_int))), \
#    byref(cast(subfunctions[8], POINTER(c_int))), nullPtr)
    subfunctions = [subf0, subf1, subf2, subf3, subf4, subf5, subf6, subf7, subf8]
    subs = []
    if arity.value > pobyso_max_arity:
        return(0,[])
    for i in xrange(arity.value):
        subs.append(int(subfunctions[i].value))
        #print subs[i]
    return(int(arity.value), subs)
    
def pobyso_get_prec():
    """ Legacy function. See pobyso_get_prec_so_sa(). """
    return(pobyso_get_prec_so_sa())

def pobyso_get_prec_so_sa():
    """
    Get the current default precision in Sollya.
    The return value is Sage/Python int.
    """
    retc = sollya_lib_get_prec(None)
    a = c_int(0)
    sollya_lib_get_constant_as_int(byref(a), retc)
    return(int(a.value))

def pobyso_get_prec_of_constant(ctExpSo):
    """ Legacy function. See pobyso_get_prec_of_constant_so_sa. """
    return(pobyso_get_prec_of_constant_so_sa(ctExpSo))

def pobyso_get_prec_of_range_so_sa(rangeSo):
    prec = c_int(0)
    retc = sollya_lib_get_prec_of_range(byref(prec), rangeSo, None)
    return(int(prec.value))

def pobyso_infnorm_so_so(func, interval, file = None, intervalList = None):
    print "Do not use this function. User pobyso_supnorm_so_so instead."
    return(None)

def pobyso_lib_init():
    sollya_lib_init(None)
    
def pobyso_name_free_variable(freeVariableName):
    """ Legacy function. See pobyso_name_free_variable_sa_so. """
    pobyso_name_free_variable_sa_so(freeVariableName)

def pobyso_name_free_variable_sa_so(freeVariableName):
    sollya_lib_name_free_variable(freeVariableName)

def pobyso_parse_string(string):
    """ Legacy function. See pobyso_parse_string_sa_so. """
    return(pobyso_parse_string_sa_so(string))
 
def pobyso_parse_string_sa_so(string):
    return(sollya_lib_parse_string(string))

def pobyso_range(rnLowerBound, rnUpperBound):
    """ Legacy function. See pobyso_range_sa_so. """
    return(pobyso_range_sa_so(rnLowerBound, rnUpperBound)) 

def pobyso_range_sa_so(rnLowerBound, rnUpperBound):
    lowerBoundSo = sollya_lib_constant(get_rn_value(rnLowerBound))
    upperBoundSo = sollya_lib_constant(get_rn_value(rnUpperBound))
    rangeSo = sollya_lib_range(lowerBoundSo, upperBoundSo)
    return(rangeSo)

def pobyso_remez_canonical_sa_sa(func, \
                                 degree, \
                                 lowerBound, \
                                 upperBound, \
                                 weight = None, \
                                 quality = None):
    """
    All arguments are Sage/Python.
    The functions (func and weight) must be passed as expressions or strings.
    Otherwise the function fails. 
    The return value is a pointer is a Sage polynomial.
    """
    var('zorglub')    # Dummy variable name for type check only.
    polySo = pobyso_remez_canonical_sa_so(func, \
                                 degree, \
                                 lowerBound, \
                                 upperBound, \
                                 weight = None, \
                                 quality = None)
    if parent(func) == parent("string"):
        functionSa = eval(func)
    # Expression test.
    elif type(func) == type(zorglub):
        functionSa = func
    maxPrecision = 0
    if polySo is None:
        return(None)
    maxPrecision = pobyso_get_max_prec_of_exp_so_sa(polySo)
    RRRR = RealField(maxPrecision)
    polynomialRing = RRRR[functionSa.variables()[0]]
    expSa = pobyso_get_sage_exp_from_sollya_exp_so_sa(polySo, RRRR)
    polySa = polynomial(expSa, polynomialRing)
    return(polySa)
    
def pobyso_remez_canonical(func, \
                           degree, \
                           lowerBound, \
                           upperBound, \
                           weight = "1", \
                           quality = None):
    """ Legacy function. See pobyso_remez_canonical_sa_so. """
    return(pobyso_remez_canonical_sa_so(func, \
                                        degree, \
                                        lowerBound, \
                                        upperBound, \
                                        weight, \
                                        quality))
def pobyso_remez_canonical_sa_so(func, \
                                 degree, \
                                 lowerBound, \
                                 upperBound, \
                                 weight = None, \
                                 quality = None):
    """
    All arguments are Sage/Python.
    The functions (func and weight) must be passed as expressions or strings.
    Otherwise the function fails. 
    The return value is a pointer to a Sollya function.
    """
    var('zorglub')    # Dummy variable name for type check only.
    currentVariableName = None
    # The func argument can be of different types (string, 
    # symbolic expression...)
    if parent(func) == parent("string"):
        functionSo = sollya_lib_parse_string(func)
    # Expression test.
    elif type(func) == type(zorglub):
        # Until we are able to translate Sage expressions into Sollya 
        # expressions : parse the string version.
        currentVariableName = func.variables()[0]
        sollya_lib_name_free_variable(str(currentVariableName))
        functionSo = sollya_lib_parse_string(func._assume_str())
    else:
        return(None)
    if weight is None:
        weightSo = pobyso_constant_1_sa_so()
    elif parent(weight) == parent("string"):
        weightSo = sollya_lib_parse_string(func)
    elif type(weight) == type(zorglub): 
        functionSo = sollya_lib_parse_string_sa_so(weight._assume_str())
    else:
        return(None)
    degreeSo = pobyso_constant_from_int(degree)
    rangeSo = pobyso_range_sa_so(lowerBound, upperBound)
    if not quality is None:
        qualitySo= pobyso_constant_sa_so(quality)
    else:
        qualitySo = None
    return(sollya_lib_remez(functionSo, \
                            degreeSo, \
                            rangeSo, \
                            weightSo, \
                            qualitySo, \
                            None))
    
def pobyso_remez_canonical_so_so(funcSo, \
                                 degreeSo, \
                                 rangeSo, \
                                 weightSo = pobyso_constant_1_sa_so(),\
                                 qualitySo = None):
    """
    All arguments are pointers to Sollya objects.
    The return value is a pointer to a Sollya function.
    """
    if not sollya_lib_obj_is_function(funcSo):
        return(None)
    return(sollya_lib_remez(funcSo, degreeSo, rangeSo, weightSo, qualitySo, None))
    
def pobyso_set_canonical_off():
    sollya_lib_set_canonical(sollya_lib_off())

def pobyso_set_canonical_on():
    sollya_lib_set_canonical(sollya_lib_on())

def pobyso_set_prec(p):
    """ Legacy function. See pobyso_set_prec_sa_so. """
    return( pobyso_set_prec_sa_so(p))

def pobyso_set_prec_sa_so(p):
    a = c_int(p)
    precSo = c_void_p(sollya_lib_constant_from_int(a))
    sollya_lib_set_prec(precSo)

def pobyso_supnorm_so_so(polySo, funcSo, intervalSo, errorTypeSo, accuracySo):
    return(sollya_lib_supnorm(polySo, funcSo, intervalSo, errorTypeSo, \
                              accuracySo))

def pobyso_taylor(function, degree, point):
    """ Legacy function. See pobysoTaylor_so_so. """
    return(pobyso_taylor_so_so(function, degree, point))

def pobyso_taylor_so_so(function, degree, point):
    return(sollya_lib_taylor(function, degree, point))
    
def pobyso_taylorform(function, degree, point = None, interval = None, errorType=None):
    """ Legacy function. See ;"""
    
def pobyso_taylorform_sa_sa(functionSa, \
                            degree, \
                            point, \
                            precision, \
                            interval=None, \
                            errorType=None):
    """
    Compute the Taylor form of 'degree' for 'functionSa' at 'point' 
    for 'interval' with 'errorType'. 
    point: must be a Real or a Real interval.
    return the Taylor form as an array
    TODO: take care of the interval and of point when it is an interval;
          when errorType is not None;
          take care of the other elements of the Taylor form (coefficients errors and
          delta.
    """
    # Absolute as the default error.
    if errorType is None:
        errorTypeSo = sollya_lib_absolute()
    else:
        #TODO: deal with the other case.
        pass
    varSa = functionSa.variables()[0]
    pointBaseRingString = str(point.base_ring())
    if not re.search('Real', pointBaseRingString):
        return None
    # Call Sollya but first "sollyafy" the arguments.
    pobyso_name_free_variable_sa_so(str(varSa))
    #pobyso_set_prec_sa_so(300)
    # Sollyafy the function.
    functionSo = pobyso_parse_string_sa_so(functionSa._assume_str())
    if sollya_lib_obj_is_error(functionSo):
        print "pobyso_tailorform: function string can't be parsed!"
        return None
    # Sollyafy the degree
    degreeSo = sollya_lib_constant_from_int(int(degree))
    # Sollyafy the point
    if not re.search('Interval', pointBaseRingString):
        pointSo  = pobyso_constant_sa_so(point)
    else:
        # TODO: deal with the interval case.
        pass
    # Call Sollya
    taylorFormSo = sollya_lib_taylorform(functionSo, degreeSo, pointSo, errorTypeSo,\
                                         None)
    (tfsAsList, numElements, isEndElliptic) = \
            pobyso_get_list_elements_so_so(taylorFormSo)
    polySo = tfsAsList[0]
    maxPrecision = pobyso_get_max_prec_of_exp_so_sa(polySo)
    polyRealField = RealField(maxPrecision)
    expSa = pobyso_get_sage_exp_from_sollya_exp_so_sa(polySo, polyRealField)
    sollya_lib_close()
    polynomialRing = polyRealField[str(varSa)]
    polySa = polynomial(expSa, polynomialRing)
    taylorFormSa = [polySa]
    return(taylorFormSa)
# End pobyso_taylor_form_sa_sa

def pobyso_taylorform_so_so(functionSo, degreeSo, pointSo, intervalSo=None, \
                            errorTypeSo=None):
    createdErrorType = False
    if errorTypeSo is None:
        errorTypeSo = sollya_lib_absolute()
        createdErrorType = True
    else:
        #TODO: deal with the other case.
        pass
    if intervalSo is None:
        resultSo = sollya_lib_taylorform(functionSo, degreeSo, pointSo, \
                                         errorTypeSo, None)
    else:
        resultSo = sollya_lib_taylorform(functionSo, degreeSo, pointSo, \
                                         intervalSo, errorTypeSo, None)
    if createdErrorType:
        sollya_lib_clear_obj(errorTypeSo)
    return(resultSo)
        

def pobyso_univar_polynomial_print_reverse(polySa):
    """ Legacy function. See pobyso_univar_polynomial_print_reverse_sa_sa. """
    return(pobyso_univar_polynomial_print_reverse_sa_sa(polySa))

def pobyso_univar_polynomial_print_reverse_sa_sa(polySa):
    """
    Return the string representation of a univariate polynomial with
    monomials ordered in the x^0..x^n order of the monomials.
    Remember: Sage
    """
    polynomialRing = polySa.base_ring()
    # A very expensive solution:
    # -create a fake multivariate polynomial field with only one variable,
    #   specifying a negative lexicographical order;
    mpolynomialRing = PolynomialRing(polynomialRing.base(), \
                                     polynomialRing.variable_name(), \
                                     1, order='neglex')
    # - convert the univariate argument polynomial into a multivariate
    #   version;
    p = mpolynomialRing(polySa)
    # - return the string representation of the converted form.
    # There is no simple str() method defined for p's class.
    return(p.__str__())
#
print "Superficial test of pobyso:"    
print pobyso_get_prec()  
pobyso_set_prec(165)
print pobyso_get_prec()  
a=100
print type(a)
id(a)
print "Max arity: ", pobyso_max_arity
print "Function tripleDouble (43) as a string: ", pobyso_function_type_as_string(43)
print "Function None (44) as a string: ", pobyso_function_type_as_string(44)