<commit_before># -*- coding: utf-8 -*-
"""
Created on Tue Mar 22 17:52:49 2016

@author: Alex Kerr

Contains class definition(s) used to minimize the energy of Molecules
"""

import sys
from math import copysign

import numpy as np

EP = sys.float_info.epsilon
SQRTEP = EP**.5
GR = 1.618

def minimize(mol, n=2500, descent="cg", search="backtrack", numgrad=False,
             eprec=1e-2, fprec=1e-2,
             efreq=1000, nbnfreq=15):
    """Minimize the energy of the inputted molecule.

    Args:
        mol (Molecule): Molecule to be energy-minimized.
    Keywords:
        n (int): Max number of iterations in minimization run(s).
        descent (str): Method in which the local energy minimum will be approached;
            must be key in descentDict
        search (str): Line search method; must be key in searchDict
        numgrad (bool): True if the gradients are to be calculated numerically;
            default is False
        eprec (float): Precision for energy changes when an iteration is made
            signalling convergence has occurred
        fprec (float): Precision for force magnitude signaling
            convergence has occurred.
        efreq (int): Iteration period in which information is printed to the user;
            called frequency despite being inverse frequency."""

    if numgrad:
        grad_routine = mol.define_gradient_routine_numerical()
    else:
        grad_routine = mol.define_gradient_routine_analytical()

    return descentDict[descent](mol, n, searchDict[search], mol.define_energy_routine(), grad_routine,
                         efreq, nbnfreq, eprec*mol.ff.eunits, fprec*mol.ff.eunits/mol.ff.lunits)

def steepest_descent(mol, n, search, calc_e, calc_grad, efreq, nbn, eprec, fprec):
    """Minimize the energy of the inputted molecule via the steepest descent approach."""

    #initial guess for stepsize
    stepSize = 1e-1

    energy = calc_e()
    gradient, maxForce, totalMag, = calc_grad()
    eList = [energy]
    print('energy:   %s' % energy)
    print('maxforce: %s' % maxForce)

    for step in range(1, n+1):

        #calculate the stepsize
        stepSize = search(mol, -gradient/totalMag, energy, gradient, calc_e, alpha=stepSize)

        #take the step
        mol.posList += stepSize*(-gradient/totalMag)

        #reset nonbonded neighbors
        if mol.ff.lj:
            if step % nbn == 0:
                mol._configure_nonbonded_neighbors()

        #reset quantities
        energy = calc_e()
        gradient, maxForce, totalMag = calc_grad()

        #for every multiple of efreq, print the status
        if step % efreq == 0:
            print('step:     %s' % step)
            print('energy:   %s' % energy)
            print('maxforce: %s' % maxForce)
            eList.append(energy)

        #break the iteration if our forces are small enough
        if maxForce < fprec:
            print('###########\n Finished! \n###########')
            print('step:     %s' % step)
            print('energy:   %s' % energy)
            print('maxforce: %s' % maxForce)
            break

    return mol, eList

def conjugate_gradient(mol, n, search, calc_e, calc_grad, efreq, nbn, eprec, fprec):
    """Minimize the energy of the inputted molecule via the conjugate gradient approach."""

    #initial guess for stepsize
    stepSize = 1e-1

    #starting values
    energy = calc_e()
    gradient, maxForce, totalMag, = calc_grad()
    eList = [energy]
    print('energy:   %s' % energy)
    print('maxforce: %s' % maxForce)

    gamma = 0.0
    prevH = np.zeros([len(mol), 3])

    for step in range(1, n+1):

        #get the step direction
        h = -gradient + gamma*prevH
        normH = h/np.linalg.norm(np.hstack(h))

        #calculate the stepsize
        stepSize = search(mol, normH, energy, gradient, calc_e, alpha=stepSize)

        #take the step
        mol.posList += stepSize*(normH)

        #reset nonbonded neighbors
        if mol.ff.lj:
            if step % nbn == 0:
                mol._configure_nonbonded_neighbors()

        #reset quantities
        prevH = h
        prevGrad = gradient
        energy = calc_e()
        gradient, maxForce, totalMag = calc_grad()
        gamma = calculate_gamma(gradient, prevGrad)

        #for every multiple of efreq, print the status
        if step % efreq == 0:
            print('step:     %s' % step)
            print('energy:   %s' % energy)
            print('maxforce: %s' % maxForce)
            eList.append(energy)

        #break the iteration if our forces are small enough
        if maxForce < fprec:
            print('###########\n Finished! \n###########')
            print('step:     %s' % step)
            print('energy:   %s' % energy)
            print('maxforce: %s' % maxForce)
            break

    return mol, eList

def parabolic_interpolation(a,b,c,fa,fb,fc):

    m = (b-a)*(fb-fc)
    n = (b-c)*(fb-fa)
    return b - ((b-c)*n - (b-a)*m)/(2.*copysign(max(abs(n-m), EP), n-m))

def line_search_backtrack(mol, stepList, e, grad, calc_e, alpha=None):
    """Return the stepsize determined by the backtracking strategies of
    Armijo and Goldstein.

    Args:
        mol (Molecule): Molecule to be minimized.  mol.posList is the coordinate array of the atoms
        stepList (ndarray):  A N x 3 array of the step direction.
        e (float): The energy of the molecule before the step is taken.
        grad (ndarray): A N x 3 array of the forces on the atoms before the step is taken.
        calc_e (function): Callable function that returns the energy of the molecule
        alpha (float): An initial guess for the step size"""

    tau = 0.5
    c = 0.33
    alpha /= tau

    m = np.dot(np.hstack(stepList),np.hstack(grad))
    if m > 0.:
        raise ValueError("Step isn't a descent!")

    t = -c*m

    counter = 0
    while alpha > EP:

        mol.posList += alpha*stepList
        newE = calc_e()
        mol.posList += -alpha*stepList
        if e - newE >= alpha*t:
#            print('counter:  %s' % counter)
            return alpha
        else:
            alpha *= tau
            counter += 1

#    print('counter:  %s' % counter)
    return EP

def line_search_brent(mol, stepList, e, grad, calc_e, alpha=None):
    """Return the stepsize determined by Brent's method

    Args:
        mol (Molecule): Molecule to be minimized.  mol.posList is the coordinate array of the atoms
        stepList (ndarray):  A N x 3 array of the step direction.
        e (float): The energy of the molecule before the step is taken.
        grad (ndarray): A N x 3 array of the forces on the atoms before the step is taken.
        calc_e (function): Callable function that returns the energy of the molecule"""

    a, b, c = bracket_minimum(mol, stepList, e, calc_e)

    return 0.

def bracket_minimum(mol, stepList, ea, calc_e):
    """Return a tuple of 3 points a,b,c such that
    f(a) > f(b) < f(c).  These points are stepsizes along the step direction
    along the potential energy surface of the molecule."""

    #a will be the zero point
    a = 0.

    #b will be some small distance away (we assume our step direction will minimize the energy within a finite range)
    b = a + SQRTEP
    mol.posList += b*stepList
    eb = calc_e()
    mol.posList += -b*stepList

    if eb > ea:
        raise ValueError("There was an error in bracketing the minimum!")

    #c will be found through an iterative process
    def ef(c):
        mol.posList += c*stepList
        e = calc_e()
        mol.posList += -c*stepList
        return e

    c = b + GR*(b-a)
    ec = ef(c)

    while ec <= eb:

        x = parabolic_interpolation(a,b,c,ea,eb,ec)
        xedge = b + 100.*(c-b)

        #if x is between b,c...
        if ((b-x)*(x-c)) > 0.:
            #check f(x)
            ex = ef(x)
            if ex < ec:
                a,b = b,x
                ea,eb = eb, ex
                continue
            elif ex > eb:
                c,ec = x,ex
                continue
            x = c + GR*(c-b)
            ex = ef(x)

        #if x is between c and our defined edge
        elif ((c-x)*(x-xedge)) > 0.:
            #check f(x)
            ex=ef(x)
            if ex < ec:
                b,c,x = c,x,c+GR*(c-b)
                eb,ec,ex = ec,ex,ef(x)

        #put x on the edge
        elif ((x-xedge)*(xedge-c)) > 0.:
            x = xedge
            ex = ef(x)

        #just slide along the search direction
        else:
            x = c + GR*(c-b)
            ex = ef(x)

        a,b,c = b,c,x
        ea,eb,ec = eb,ec,ex

    return a, b, c

descentDict = {"sd":steepest_descent, "cg":conjugate_gradient}
searchDict = {"backtrack":line_search_backtrack, "brent":line_search_brent}

def calculate_gamma(grad, pgrad):
    """Return the 'gamma' factor in the conjugate gradient method
    according to Fletcher and Reeves."""
    grad = np.hstack(grad)
    pgrad = np.hstack(pgrad)
    return (np.dot(grad,grad))/(np.dot(pgrad,pgrad))<commit_msg>Make print statements optional in conjugate_gradients minimization function<commit_after># -*- coding: utf-8 -*-
"""
Created on Tue Mar 22 17:52:49 2016

@author: Alex Kerr

Contains class definition(s) used to minimize the energy of Molecules
"""

import sys
from math import copysign

import numpy as np

EP = sys.float_info.epsilon
SQRTEP = EP**.5
GR = 1.618

def minimize(mol, n=2500, descent="cg", search="backtrack", numgrad=False,
             eprec=1e-2, fprec=1e-2,
             efreq=1000, nbnfreq=15, print_=True):
    """Minimize the energy of the inputted molecule.

    Args:
        mol (Molecule): Molecule to be energy-minimized.
    Keywords:
        n (int): Max number of iterations in minimization run(s).
        descent (str): Method in which the local energy minimum will be approached;
            must be key in descentDict
        search (str): Line search method; must be key in searchDict
        numgrad (bool): True if the gradients are to be calculated numerically;
            default is False
        eprec (float): Precision for energy changes when an iteration is made
            signalling convergence has occurred
        fprec (float): Precision for force magnitude signaling
            convergence has occurred.
        efreq (int): Iteration period in which information is printed to the user;
            called frequency despite being inverse frequency."""

    if numgrad:
        grad_routine = mol.define_gradient_routine_numerical()
    else:
        grad_routine = mol.define_gradient_routine_analytical()

    return descentDict[descent](mol, n, searchDict[search], mol.define_energy_routine(), grad_routine,
                         efreq, nbnfreq, eprec*mol.ff.eunits, fprec*mol.ff.eunits/mol.ff.lunits,
                         print_=print_)

def steepest_descent(mol, n, search, calc_e, calc_grad, efreq, nbn, eprec, fprec):
    """Minimize the energy of the inputted molecule via the steepest descent approach."""

    #initial guess for stepsize
    stepSize = 1e-1

    energy = calc_e()
    gradient, maxForce, totalMag, = calc_grad()
    eList = [energy]
    print('energy:   %s' % energy)
    print('maxforce: %s' % maxForce)

    for step in range(1, n+1):

        #calculate the stepsize
        stepSize = search(mol, -gradient/totalMag, energy, gradient, calc_e, alpha=stepSize)

        #take the step
        mol.posList += stepSize*(-gradient/totalMag)

        #reset nonbonded neighbors
        if mol.ff.lj:
            if step % nbn == 0:
                mol._configure_nonbonded_neighbors()

        #reset quantities
        energy = calc_e()
        gradient, maxForce, totalMag = calc_grad()

        #for every multiple of efreq, print the status
        if step % efreq == 0:
            print('step:     %s' % step)
            print('energy:   %s' % energy)
            print('maxforce: %s' % maxForce)
            eList.append(energy)

        #break the iteration if our forces are small enough
        if maxForce < fprec:
            print('###########\n Finished! \n###########')
            print('step:     %s' % step)
            print('energy:   %s' % energy)
            print('maxforce: %s' % maxForce)
            break

    return mol, eList

def conjugate_gradient(mol, n, search, calc_e, calc_grad, efreq, nbn, eprec, fprec,
                       print_=True):
    """Minimize the energy of the inputted molecule via the conjugate gradient approach."""

    #initial guess for stepsize
    stepSize = 1e-1

    #starting values
    energy = calc_e()
    gradient, maxForce, totalMag, = calc_grad()
    eList = [energy]
    if print_:
        print('energy:   %s' % energy)
        print('maxforce: %s' % maxForce)

    gamma = 0.0
    prevH = np.zeros([len(mol), 3])

    for step in range(1, n+1):

        #get the step direction
        h = -gradient + gamma*prevH
        normH = h/np.linalg.norm(np.hstack(h))

        #calculate the stepsize
        stepSize = search(mol, normH, energy, gradient, calc_e, alpha=stepSize)

        #take the step
        mol.posList += stepSize*(normH)

        #reset nonbonded neighbors
        if mol.ff.lj:
            if step % nbn == 0:
                mol._configure_nonbonded_neighbors()

        #reset quantities
        prevH = h
        prevGrad = gradient
        energy = calc_e()
        gradient, maxForce, totalMag = calc_grad()
        gamma = calculate_gamma(gradient, prevGrad)

        #for every multiple of efreq, print the status
        if step % efreq == 0 & print_:
            print('step:     %s' % step)
            print('energy:   %s' % energy)
            print('maxforce: %s' % maxForce)
            eList.append(energy)

        #break the iteration if our forces are small enough
        if maxForce < fprec & print_:
            print('###########\n Finished! \n###########')
            print('step:     %s' % step)
            print('energy:   %s' % energy)
            print('maxforce: %s' % maxForce)
            break

    return mol, eList

def parabolic_interpolation(a,b,c,fa,fb,fc):

    m = (b-a)*(fb-fc)
    n = (b-c)*(fb-fa)
    return b - ((b-c)*n - (b-a)*m)/(2.*copysign(max(abs(n-m), EP), n-m))

def line_search_backtrack(mol, stepList, e, grad, calc_e, alpha=None):
    """Return the stepsize determined by the backtracking strategies of
    Armijo and Goldstein.

    Args:
        mol (Molecule): Molecule to be minimized.  mol.posList is the coordinate array of the atoms
        stepList (ndarray):  A N x 3 array of the step direction.
        e (float): The energy of the molecule before the step is taken.
        grad (ndarray): A N x 3 array of the forces on the atoms before the step is taken.
        calc_e (function): Callable function that returns the energy of the molecule
        alpha (float): An initial guess for the step size"""

    tau = 0.5
    c = 0.33
    alpha /= tau

    m = np.dot(np.hstack(stepList),np.hstack(grad))
    if m > 0.:
        raise ValueError("Step isn't a descent!")

    t = -c*m

    counter = 0
    while alpha > EP:

        mol.posList += alpha*stepList
        newE = calc_e()
        mol.posList += -alpha*stepList
        if e - newE >= alpha*t:
#            print('counter:  %s' % counter)
            return alpha
        else:
            alpha *= tau
            counter += 1

#    print('counter:  %s' % counter)
    return EP

def line_search_brent(mol, stepList, e, grad, calc_e, alpha=None):
    """Return the stepsize determined by Brent's method

    Args:
        mol (Molecule): Molecule to be minimized.  mol.posList is the coordinate array of the atoms
        stepList (ndarray):  A N x 3 array of the step direction.
        e (float): The energy of the molecule before the step is taken.
        grad (ndarray): A N x 3 array of the forces on the atoms before the step is taken.
        calc_e (function): Callable function that returns the energy of the molecule"""

    a, b, c = bracket_minimum(mol, stepList, e, calc_e)

    return 0.

def bracket_minimum(mol, stepList, ea, calc_e):
    """Return a tuple of 3 points a,b,c such that
    f(a) > f(b) < f(c).  These points are stepsizes along the step direction
    along the potential energy surface of the molecule."""

    #a will be the zero point
    a = 0.

    #b will be some small distance away (we assume our step direction will minimize the energy within a finite range)
    b = a + SQRTEP
    mol.posList += b*stepList
    eb = calc_e()
    mol.posList += -b*stepList

    if eb > ea:
        raise ValueError("There was an error in bracketing the minimum!")

    #c will be found through an iterative process
    def ef(c):
        mol.posList += c*stepList
        e = calc_e()
        mol.posList += -c*stepList
        return e

    c = b + GR*(b-a)
    ec = ef(c)

    while ec <= eb:

        x = parabolic_interpolation(a,b,c,ea,eb,ec)
        xedge = b + 100.*(c-b)

        #if x is between b,c...
        if ((b-x)*(x-c)) > 0.:
            #check f(x)
            ex = ef(x)
            if ex < ec:
                a,b = b,x
                ea,eb = eb, ex
                continue
            elif ex > eb:
                c,ec = x,ex
                continue
            x = c + GR*(c-b)
            ex = ef(x)

        #if x is between c and our defined edge
        elif ((c-x)*(x-xedge)) > 0.:
            #check f(x)
            ex=ef(x)
            if ex < ec:
                b,c,x = c,x,c+GR*(c-b)
                eb,ec,ex = ec,ex,ef(x)

        #put x on the edge
        elif ((x-xedge)*(xedge-c)) > 0.:
            x = xedge
            ex = ef(x)

        #just slide along the search direction
        else:
            x = c + GR*(c-b)
            ex = ef(x)

        a,b,c = b,c,x
        ea,eb,ec = eb,ec,ex

    return a, b, c

descentDict = {"sd":steepest_descent, "cg":conjugate_gradient}
searchDict = {"backtrack":line_search_backtrack, "brent":line_search_brent}

def calculate_gamma(grad, pgrad):
    """Return the 'gamma' factor in the conjugate gradient method
    according to Fletcher and Reeves."""
    grad = np.hstack(grad)
    pgrad = np.hstack(pgrad)
    return (np.dot(grad,grad))/(np.dot(pgrad,pgrad))<|endoftext|>


<commit_before>from abc import ABCMeta, abstractmethod

from all_known import all_known
from eeyinterface import implements_interface
from usererrorexception import EeyUserErrorException

# -- Base class and global methods ---

class EeyValue( object ):

    __metaclass__ = ABCMeta

    def __init__( self ):
        self.cached_eval = None

    def render( self, env ):
        return env.render_value( self.evaluate( env ) )

    def is_known( self, env ):
        return True

    def evaluate( self, env ):
        if self.cached_eval is None:
            self.cached_eval = self.do_evaluate( env )
        return self.cached_eval

    def do_evaluate( self, env ):
        return self

    def evaluated_type( self, env ):
        return self.__class__

    @abstractmethod
    def construction_args( self ): pass

    def __repr__( self ):
        return "%s(%s)" % (
            self.__class__.__name__,
            ",".join( repr(x) for x in self.construction_args() )
            )

# --- Specific value types ---

class EeyVariable( EeyValue ):
    def __init__( self, clazz ):
        EeyValue.__init__( self )
        self.clazz = clazz

    def construction_args( self ):
        return ( self.clazz, )

    def is_known( self, env ):
        return False

    def evaluated_type( self, env ):
        return self.clazz

class EeySymbol( EeyValue ):
    def __init__( self, symbol_name ):
        EeyValue.__init__( self )
        self.symbol_name = symbol_name

    def construction_args( self ):
        return ( self.symbol_name, )

    def _lookup( self, env ):
        if self.symbol_name not in env.namespace:
            raise EeyUserErrorException( "The symbol '%s' is not defined." %
                self.symbol_name )
            # TODO: line, column, filename

        return env.namespace[self.symbol_name]

    def name( self ):
        # TODO: delete this method, or use it consistently
        return self.symbol_name

    def do_evaluate( self, env ):
        # Look up this symbol in the namespace of our environment
        value = self._lookup( env ).evaluate( env )

        if value.is_known( env ):
            # Pass back what we looked up
            return value
        elif implements_interface( value, EeySymbol ):
            return value
        else:
            # If what we find is a variable (i.e. something unknown until
            # runtime) then we simply return ourselves: for the purpose of
            # rendering, this _is_ a symbol.
            return self

    def is_known( self, env ):
        return self._lookup( env ).is_known( env )

    def evaluated_type( self, env ):
        return self._lookup( env ).evaluated_type( env )

class EeyBool( EeyValue ):
    def __init__( self, value ):
        EeyValue.__init__( self )
        self.value = value

    def construction_args( self ):
        return ( self.value, )

class EeyInt( EeyValue ):
    def __init__( self,  str_int ):
        EeyValue.__init__( self )
        self.value = str( str_int )

    def construction_args( self ):
        return ( self.value, )

    def plus( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle large numbers
        return EeyInt( str( int( self.value ) + int( other.value ) ) )

    def times( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle large numbers
        return EeyInt( str( int( self.value ) * int( other.value ) ) )

    def greater_than( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle large numbers
        return EeyBool( int( self.value ) > int( other.value ) )

class EeyFloat( EeyValue ):
    def __init__( self,  str_float ):
        EeyValue.__init__( self )
        self.value = str( str_float )

    def construction_args( self ):
        return ( self.value, )

    def plus( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle arbitrary numbers
        return EeyFloat( str( float( self.value ) + float( other.value ) ) )

    def times( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle arbitrary numbers
        return EeyFloat( str( float( self.value ) * float( other.value ) ) )

    def greater_than( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle arbitrary numbers
        return EeyBool( float( self.value ) > float( other.value ) )

class EeyNoneType( EeyValue ):
    def construction_args( self ):
        return ()

eey_none = EeyNoneType()

class EeyVoid( EeyValue ):
    def construction_args( self ):
        return ()

class EeyString( EeyValue ):
    def __init__( self, py_str ):
        EeyValue.__init__( self )
        self.value = py_str

    def construction_args( self ):
        return ( self.value, )

    def as_py_str( self ):
        return self.value

class EeyPlus( EeyValue ):
    def __init__( self, left_value, right_value ):
        EeyValue.__init__( self )
        # TODO: assert( all( is_plusable, ( left_value, right_value ) )
        self.left_value  = left_value
        self.right_value = right_value

    def construction_args( self ):
        return ( self.left_value, self.right_value )

    def do_evaluate( self, env ):
        if self.is_known( env ):
            return self.left_value.evaluate( env ).plus(
                self.right_value.evaluate( env ) )
        else:
            return self

    def evaluated_type( self, env ):
        return self.left_value.evaluated_type( env )

    def is_known( self, env ):
        return all_known( ( self.left_value, self.right_value ), env )

class EeyTimes( EeyValue ):
    def __init__( self, left_value, right_value ):
        EeyValue.__init__( self )
        # TODO: assert( all( is_timesable, ( left_value, right_value ) )
        self.left_value  = left_value
        self.right_value = right_value

    def construction_args( self ):
        return ( self.left_value, self.right_value )

    def do_evaluate( self, env ):
        if self.is_known( env ):
            return self.left_value.evaluate( env ).times(
                self.right_value.evaluate( env ) )
        else:
            return self

    def evaluated_type( self, env ):
        return self.left_value.evaluated_type( env )

    def is_known( self, env ):
        return all_known( ( self.left_value, self.right_value ), env )

class EeyGreaterThan( EeyValue ):
    def __init__( self, left_value, right_value ):
        EeyValue.__init__( self )
        # TODO: assert( all( is_gtable, ( left_value, right_value ) )
        self.left_value  = left_value
        self.right_value = right_value

    def construction_args( self ):
        return ( self.left_value, self.right_value )

    def do_evaluate( self, env ):
        if self.is_known( env ):
            return self.left_value.evaluate( env ).greater_than(
                self.right_value.evaluate( env ) )
        else:
            return self

    def is_known( self, env ):
        return all_known( ( self.left_value, self.right_value ), env )

class EeyPass( EeyValue ):
    """A statement that does nothing."""

    def __init__( self ):
        EeyValue.__init__( self )

    def construction_args( self ):
        return ()

class EeyType( EeyValue ):
    def __init__( self, value ):
        EeyValue.__init__( self )
        # TODO: check we have been passed a type
        self.value = value

    def construction_args( self ):
        return ( self.value, )

    def __eq__( self, other ):
        return (
            self.__class__ == other.__class__ and
            self.value == other.value
        )

    def __ne__( self, other ):
        return not self.__eq__( other )

class EeyArray( EeyValue ):
    def __init__( self, value_type, values ):
        EeyValue.__init__( self )
        self.value_type = value_type
        self.values = values

    def construction_args( self ):
        return ( self.value_type, self.values )

    def get_index( self, int_index ):
        return self.values[int_index]

<commit_msg>Refactor binary operator code to share some implementation.<commit_after>from abc import ABCMeta, abstractmethod

from all_known import all_known
from eeyinterface import implements_interface
from usererrorexception import EeyUserErrorException

# -- Base class and global methods ---

class EeyValue( object ):

    __metaclass__ = ABCMeta

    def __init__( self ):
        self.cached_eval = None

    def render( self, env ):
        return env.render_value( self.evaluate( env ) )

    def is_known( self, env ):
        return True

    def evaluate( self, env ):
        if self.cached_eval is None:
            self.cached_eval = self.do_evaluate( env )
        return self.cached_eval

    def do_evaluate( self, env ):
        return self

    def evaluated_type( self, env ):
        return self.__class__

    @abstractmethod
    def construction_args( self ): pass

    def __repr__( self ):
        return "%s(%s)" % (
            self.__class__.__name__,
            ",".join( repr(x) for x in self.construction_args() )
            )

# --- Specific value types ---

class EeyVariable( EeyValue ):
    def __init__( self, clazz ):
        EeyValue.__init__( self )
        self.clazz = clazz

    def construction_args( self ):
        return ( self.clazz, )

    def is_known( self, env ):
        return False

    def evaluated_type( self, env ):
        return self.clazz

class EeySymbol( EeyValue ):
    def __init__( self, symbol_name ):
        EeyValue.__init__( self )
        self.symbol_name = symbol_name

    def construction_args( self ):
        return ( self.symbol_name, )

    def _lookup( self, env ):
        if self.symbol_name not in env.namespace:
            raise EeyUserErrorException( "The symbol '%s' is not defined." %
                self.symbol_name )
            # TODO: line, column, filename

        return env.namespace[self.symbol_name]

    def name( self ):
        # TODO: delete this method, or use it consistently
        return self.symbol_name

    def do_evaluate( self, env ):
        # Look up this symbol in the namespace of our environment
        value = self._lookup( env ).evaluate( env )

        if value.is_known( env ):
            # Pass back what we looked up
            return value
        elif implements_interface( value, EeySymbol ):
            return value
        else:
            # If what we find is a variable (i.e. something unknown until
            # runtime) then we simply return ourselves: for the purpose of
            # rendering, this _is_ a symbol.
            return self

    def is_known( self, env ):
        return self._lookup( env ).is_known( env )

    def evaluated_type( self, env ):
        return self._lookup( env ).evaluated_type( env )

class EeyBool( EeyValue ):
    def __init__( self, value ):
        EeyValue.__init__( self )
        self.value = value

    def construction_args( self ):
        return ( self.value, )

class EeyInt( EeyValue ):
    def __init__( self,  str_int ):
        EeyValue.__init__( self )
        self.value = str( str_int )

    def construction_args( self ):
        return ( self.value, )

    def plus( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle large numbers
        return EeyInt( str( int( self.value ) + int( other.value ) ) )

    def times( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle large numbers
        return EeyInt( str( int( self.value ) * int( other.value ) ) )

    def greater_than( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle large numbers
        return EeyBool( int( self.value ) > int( other.value ) )

class EeyFloat( EeyValue ):
    def __init__( self,  str_float ):
        EeyValue.__init__( self )
        self.value = str( str_float )

    def construction_args( self ):
        return ( self.value, )

    def plus( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle arbitrary numbers
        return EeyFloat( str( float( self.value ) + float( other.value ) ) )

    def times( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle arbitrary numbers
        return EeyFloat( str( float( self.value ) * float( other.value ) ) )

    def greater_than( self, other ):
        assert other.__class__ == self.__class__
        # TODO: handle arbitrary numbers
        return EeyBool( float( self.value ) > float( other.value ) )

class EeyNoneType( EeyValue ):
    def construction_args( self ):
        return ()

eey_none = EeyNoneType()

class EeyVoid( EeyValue ):
    def construction_args( self ):
        return ()

class EeyString( EeyValue ):
    def __init__( self, py_str ):
        EeyValue.__init__( self )
        self.value = py_str

    def construction_args( self ):
        return ( self.value, )

    def as_py_str( self ):
        return self.value

class EeyBinaryOp( EeyValue ):
    def __init__( self, left_value, right_value ):
        EeyValue.__init__( self )
        # TODO: assert( all( self.is_applicable, ( left_value, right_value ) )
        self.left_value  = left_value
        self.right_value = right_value

    def construction_args( self ):
        return ( self.left_value, self.right_value )

    def do_evaluate( self, env ):
        if self.is_known( env ):
            lv = self.left_value.evaluate( env )
            rv = self.right_value.evaluate( env )
            return self.operator( lv, rv )
        else:
            return self

    def evaluated_type( self, env ):
        return self.left_value.evaluated_type( env )

    def is_known( self, env ):
        return all_known( ( self.left_value, self.right_value ), env )

class EeyPlus( EeyBinaryOp ):
    def operator( self, lv, rv ):
        return lv.plus( rv )

class EeyTimes( EeyBinaryOp ):
    def operator( self, lv, rv ):
        return lv.times( rv )

class EeyGreaterThan( EeyBinaryOp ):
    def operator( self, lv, rv ):
        return lv.greater_than( rv )

class EeyPass( EeyValue ):
    """A statement that does nothing."""

    def __init__( self ):
        EeyValue.__init__( self )

    def construction_args( self ):
        return ()

class EeyType( EeyValue ):
    def __init__( self, value ):
        EeyValue.__init__( self )
        # TODO: check we have been passed a type
        self.value = value

    def construction_args( self ):
        return ( self.value, )

    def __eq__( self, other ):
        return (
            self.__class__ == other.__class__ and
            self.value == other.value
        )

    def __ne__( self, other ):
        return not self.__eq__( other )

class EeyArray( EeyValue ):
    def __init__( self, value_type, values ):
        EeyValue.__init__( self )
        self.value_type = value_type
        self.values = values

    def construction_args( self ):
        return ( self.value_type, self.values )

    def get_index( self, int_index ):
        return self.values[int_index]

<|endoftext|>


<commit_before>""" Resizing Torch layers. """
import torch
import torch.nn as nn
import torch.nn.functional as F

from ..utils import get_shape

class IncreaseDim(nn.Module):
    """ Increase dimensionality of passed tensor by one. """
    def __init__(self, dim=1):
        super().__init__()
        self.dim = dim

    def forward(self, x):
        dim = len(get_shape(x)) - 2 + self.dim
        ones = [1] * dim
        return x.view(x.size(0), -1, *ones)

class ReduceDim(nn.Module):
    """ Reduce dimensionality of passed tensor by one. """
    def __init__(self, dim=1):
        super().__init__()
        self.dim = dim

    def forward(self, x):
        dim = max(len(get_shape(x)) - 2 - self.dim, 0)
        ones = [1] * dim
        return x.view(x.size(0), -1, *ones)

class Reshape(nn.Module):
    """ Enforce desired shape of tensor. """
    def __init__(self, shape=None, reshape_to=None):
        super().__init__()
        self.shape = shape or reshape_to

    def forward(self, x):
        return x.view(x.size(0), *self.shape)

class Interpolate(nn.Module):
    """ Upsample inputs with a given factor.

    Notes
    -----
    This is just a wrapper around ``F.interpolate``.

    For brevity ``mode`` can be specified with the first letter only: 'n', 'l', 'b', 't'.

    All the parameters should the specified as keyword arguments (i.e. with names and values).
    """
    MODES = {
        'n': 'nearest',
        'l': 'linear',
        'b': 'bilinear',
        't': 'trilinear',
    }

    def __init__(self, mode='b', size=None, shape=None, scale_factor=None, **kwargs):
        super().__init__()
        self.size, self.scale_factor = size or shape, scale_factor

        if mode in self.MODES:
            mode = self.MODES[mode]
        self.mode = mode
        self.kwargs = kwargs

    def forward(self, x):
        return F.interpolate(x, mode=self.mode, size=self.size, scale_factor=self.scale_factor,
                             align_corners=True, **self.kwargs)

    def extra_repr(self):
        if self.scale_factor is not None:
            info = 'scale_factor=' + str(self.scale_factor)
        else:
            info = 'size=' + str(self.size)
        info += ', mode=' + self.mode
        return info

class PixelShuffle(nn.PixelShuffle):
    """ Resize input tensor with depth to space operation. """
    def __init__(self, upscale_factor=None):
        super().__init__(upscale_factor)

class SubPixelConv(PixelShuffle):
    """ An alias for PixelShuffle. """
    pass

class Crop(nn.Module):
    """ Crop tensor to desired shape.

    Parameters
    ----------
    inputs
        Input tensor.
    resize_to : tuple or torch.Tensor
        Tensor or shape to resize input tensor to.
    """
    def __init__(self, resize_to):
        super().__init__()

        self.resize_to = resize_to

    def forward(self, inputs):
        i_shape = get_shape(inputs)
        r_shape = get_shape(self.resize_to)
        if (i_shape[2] > r_shape[2]) or (i_shape[3] > r_shape[3]):
            # Decrease input tensor's shape by slicing desired shape out of it
            shape = [slice(None, c) for c in r_shape[2:]]
            shape = tuple([slice(None, None), slice(None, None)] + shape)
            output = inputs[shape]
        elif (i_shape[2] < r_shape[2]) or (i_shape[3] < r_shape[3]):
            # Increase input tensor's shape by zero padding
            output = torch.zeros(*i_shape[:2], *r_shape[2:])
            output[:, :, :i_shape[2], :i_shape[3]] = inputs
        else:
            output = inputs
        return output

class Upsample(nn.Module):
    """ Upsample inputs with a given factor.

    Parameters
    ----------
    inputs
        Input tensor.
    factor : int
        Upsamping scale.
    shape : tuple of int
        Shape to upsample to (used by bilinear and NN resize).
    layout : str
        Resizing technique, a sequence of:

        - b - bilinear resize
        - N - nearest neighbor resize
        - t - transposed convolution
        - T - separable transposed convolution
        - X - subpixel convolution

        all other :class:`~.torch.ConvBlock` layers are also allowed.

    Examples
    --------
    A simple bilinear upsampling::

        x = Upsample(layout='b', shape=(256, 256), inputs=inputs)

    Upsampling with non-linear normalized transposed convolution::

        x = Upsample(layout='nat', factor=2, kernel_size=3, inputs=inputs)

    Subpixel convolution::

        x = Upsample(layout='X', factor=2, inputs=inputs)
    """
    def __init__(self, factor=2, shape=None, layout='b', inputs=None, **kwargs):
        from .conv_block import ConvBlock # can't be imported in the file beginning due to recursive imports
        super().__init__()

        if 't' in layout or 'T' in layout:
            kwargs['kernel_size'] = kwargs.get('kernel_size') or factor
            kwargs['strides'] = kwargs.get('strides') or factor
            kwargs['filters'] = kwargs.get('filters') or 'same'

        self.layer = ConvBlock(inputs=inputs, layout=layout, factor=factor, shape=shape, **kwargs)

    def forward(self, x):
        return self.layer(x)

class SEBlock(nn.Module):
    """ Squeeze and excitation block.

    Hu J. et al. "`Squeeze-and-Excitation Networks <https://arxiv.org/abs/1709.01507>`_"

    Parameters
    ----------
    ratio : int
        Squeeze ratio for the number of filters.
    squeeze_layout : str
        Operations of tensor processing.
    squeeze_units : int or sequence of ints
        Sizes of dense layers.
    squeeze_activations : str or sequence of str
        Activations of dense layers.
    """
    def __init__(self, inputs=None, ratio=4, squeeze_layout='Vfafa', squeeze_units=None, squeeze_activations=None):
        from .conv_block import ConvBlock # can't be imported in the file beginning due to recursive imports
        super().__init__()
        in_units = get_shape(inputs)[1]
        units = squeeze_units or [in_units // ratio, in_units]
        activations = squeeze_activations or ['relu', 'sigmoid']

        self.layer = ConvBlock(layout=squeeze_layout, units=units, activations=activations, inputs=inputs)

    def forward(self, x):
        x = self.layer(x)
        return x.view(x.size(0), -1, 1, 1)

class SideBlock(nn.Module):
    """ Add side branch to a :class:`~.layers.ConvBlock`. """
    def __init__(self, inputs=None, **kwargs):
        from .conv_block import ConvBlock # can't be imported in the file beginning due to recursive imports
        super().__init__()
        self.layer = ConvBlock(inputs=inputs, **kwargs)

    def forward(self, x):
        return self.layer(x)

class Combine(nn.Module):
    """ Combine list of tensor into one.

    Parameters
    ----------
    inputs : sequence of torch.Tensors
        Tensors to combine.

    op : str or callable
        If callable, then operation to be applied to the list of inputs.
        If 'concat', 'cat', '.', then inputs are concated along channels axis.
        If 'sum', '+', then inputs are summed.
        If 'mul', '*', then inputs are multiplied.
        If 'avg', then inputs are averaged.
        If 'softsum', '&', then every tensor is passed through 1x1 convolution in order to have
        the same number of channels as the first tensor, and then summed.
    """
    @staticmethod
    def concat(inputs):
        return torch.cat(inputs, dim=1)

    @staticmethod
    def sum(inputs):
        return torch.stack(inputs, dim=0).sum(dim=0)

    @staticmethod
    def mul(inputs):
        """ Multiplication. """
        result = 1
        for item in inputs:
            result = result * item
        return result

    @staticmethod
    def mean(inputs):
        return torch.mean(inputs)

    @staticmethod
    def softsum(self, inputs):
        """ Softsum. """
        #pylint: disable=bad-staticmethod-argument
        inputs = [conv(tensor) for conv, tensor in zip(self.conv, inputs)]
        return torch.stack(inputs, dim=0).sum(dim=0)

    OPS = {
        concat.__func__: ['concat', 'cat', '.'],
        sum.__func__: ['sum', 'plus', '+'],
        mul.__func__: ['multi', 'mul', '*'],
        mean.__func__: ['average', 'avg', 'mean'],
        softsum.__func__: ['softsum', '&'],
    }

    OPS = {alias: method for method, aliases in OPS.items() for alias in aliases}
    ALL_OPS = list(OPS.keys())

    def __init__(self, inputs=None, op='concat'):
        from .conv_block import ConvBlock # can't be imported in the file beginning due to recursive imports
        super().__init__()

        self.op = op
        if op in self.OPS and self.OPS[op].__name__ == 'softsum':
            args = dict(layout='c', filters=get_shape(inputs[0])[1],
                        kernel_size=1)
            conv = [ConvBlock(inputs=tensor, **args) for tensor in inputs]
            self.conv = nn.ModuleList(conv)
            self.op = lambda inputs: self.OPS[op](self, inputs)

    def spatial_resize(self, inputs):
        """ Force the same shapes of the inputs, if needed. """
        shape_ = get_shape(inputs[0])
        spatial_shape_ = shape_[len(shape_)-2:]

        resized = []
        for item in inputs:
            shape = get_shape(item)
            dim = len(shape) - 2
            spatial_shape = shape[dim:]
            if dim > 0 and spatial_shape_ != tuple([1]*dim) and spatial_shape != spatial_shape_:
                item = Crop(inputs[0])(item)
            resized.append(item)
        return resized

    def forward(self, inputs):
        if callable(self.op):
            return self.op(inputs)
        inputs = self.spatial_resize(inputs)
        if self.op in self.OPS:
            return self.OPS[self.op](inputs)
        raise ValueError('Combine operation must be a callable or \
                          one from {}, instead got {}.'.format(self.ALL_OPS, self.op))

    def extra_repr(self):
        if isinstance(self.op, str):
            return 'op=' + self.op
        return 'op=' + 'callable ' + self.op.__name__
<commit_msg>Fix resize layers<commit_after>""" Resizing Torch layers. """
import torch
import torch.nn as nn
import torch.nn.functional as F

from ..utils import get_shape, get_num_dims

class IncreaseDim(nn.Module):
    """ Increase dimensionality of passed tensor by one. """
    def __init__(self, dim=1):
        super().__init__()
        self.dim = dim

    def forward(self, x):
        dim = get_num_dims(x) + self.dim
        ones = [1] * dim
        return x.view(x.size(0), -1, *ones)

class ReduceDim(nn.Module):
    """ Reduce dimensionality of passed tensor by one. """
    def __init__(self, dim=1):
        super().__init__()
        self.dim = dim

    def forward(self, x):
        dim = max(get_num_dims(x) - self.dim, 0)
        ones = [1] * dim
        return x.view(x.size(0), -1, *ones)

class Reshape(nn.Module):
    """ Enforce desired shape of tensor. """
    def __init__(self, shape=None, reshape_to=None):
        super().__init__()
        self.shape = shape or reshape_to

    def forward(self, x):
        return x.view(x.size(0), *self.shape)

class Interpolate(nn.Module):
    """ Upsample inputs with a given factor.

    Notes
    -----
    This is just a wrapper around ``F.interpolate``.

    For brevity ``mode`` can be specified with the first letter only: 'n', 'l', 'b', 't'.

    All the parameters should the specified as keyword arguments (i.e. with names and values).
    """
    MODES = {
        'n': 'nearest',
        'l': 'linear',
        'b': 'bilinear',
        't': 'trilinear',
    }

    def __init__(self, mode='b', size=None, shape=None, scale_factor=None, **kwargs):
        super().__init__()
        self.size, self.scale_factor = size or shape, scale_factor

        if mode in self.MODES:
            mode = self.MODES[mode]
        self.mode = mode
        self.kwargs = kwargs

    def forward(self, x):
        return F.interpolate(x, mode=self.mode, size=self.size, scale_factor=self.scale_factor,
                             align_corners=True, **self.kwargs)

    def extra_repr(self):
        if self.scale_factor is not None:
            info = 'scale_factor=' + str(self.scale_factor)
        else:
            info = 'size=' + str(self.size)
        info += ', mode=' + self.mode
        return info

class PixelShuffle(nn.PixelShuffle):
    """ Resize input tensor with depth to space operation. """
    def __init__(self, upscale_factor=None):
        super().__init__(upscale_factor)

class SubPixelConv(PixelShuffle):
    """ An alias for PixelShuffle. """
    pass

class Crop(nn.Module):
    """ Crop tensor to desired shape.

    Parameters
    ----------
    inputs
        Input tensor.
    resize_to : tuple or torch.Tensor
        Tensor or shape to resize input tensor to.
    """
    def __init__(self, resize_to):
        super().__init__()

        self.resize_to = resize_to

    def forward(self, inputs):
        i_shape = get_shape(inputs)
        r_shape = get_shape(self.resize_to)
        if (i_shape[2] > r_shape[2]) or (i_shape[3] > r_shape[3]):
            # Decrease input tensor's shape by slicing desired shape out of it
            shape = [slice(None, c) for c in r_shape[2:]]
            shape = tuple([slice(None, None), slice(None, None)] + shape)
            output = inputs[shape]
        elif (i_shape[2] < r_shape[2]) or (i_shape[3] < r_shape[3]):
            # Increase input tensor's shape by zero padding
            output = torch.zeros(*i_shape[:2], *r_shape[2:])
            output[:, :, :i_shape[2], :i_shape[3]] = inputs
        else:
            output = inputs
        return output

class Upsample(nn.Module):
    """ Upsample inputs with a given factor.

    Parameters
    ----------
    inputs
        Input tensor.
    factor : int
        Upsamping scale.
    shape : tuple of int
        Shape to upsample to (used by bilinear and NN resize).
    layout : str
        Resizing technique, a sequence of:

        - b - bilinear resize
        - N - nearest neighbor resize
        - t - transposed convolution
        - T - separable transposed convolution
        - X - subpixel convolution

        all other :class:`~.torch.ConvBlock` layers are also allowed.

    Examples
    --------
    A simple bilinear upsampling::

        x = Upsample(layout='b', shape=(256, 256), inputs=inputs)

    Upsampling with non-linear normalized transposed convolution::

        x = Upsample(layout='nat', factor=2, kernel_size=3, inputs=inputs)

    Subpixel convolution::

        x = Upsample(layout='X', factor=2, inputs=inputs)
    """
    def __init__(self, factor=2, shape=None, layout='b', inputs=None, **kwargs):
        from .conv_block import ConvBlock # can't be imported in the file beginning due to recursive imports
        super().__init__()

        if 't' in layout or 'T' in layout:
            kwargs['kernel_size'] = kwargs.get('kernel_size') or factor
            kwargs['strides'] = kwargs.get('strides') or factor
            kwargs['filters'] = kwargs.get('filters') or 'same'

        self.layer = ConvBlock(inputs=inputs, layout=layout, factor=factor, shape=shape, **kwargs)

    def forward(self, x):
        return self.layer(x)

class SEBlock(nn.Module):
    """ Squeeze and excitation block.

    Hu J. et al. "`Squeeze-and-Excitation Networks <https://arxiv.org/abs/1709.01507>`_"

    Parameters
    ----------
    ratio : int
        Squeeze ratio for the number of filters.
    squeeze_layout : str
        Operations of tensor processing.
    squeeze_units : int or sequence of ints
        Sizes of dense layers.
    squeeze_activations : str or sequence of str
        Activations of dense layers.
    """
    def __init__(self, inputs=None, ratio=4, squeeze_layout='Vfafa', squeeze_units=None, squeeze_activations=None):
        from .conv_block import ConvBlock # can't be imported in the file beginning due to recursive imports
        super().__init__()
        in_units = get_shape(inputs)[1]
        units = squeeze_units or [in_units // ratio, in_units]
        activations = squeeze_activations or ['relu', 'sigmoid']

        self.layer = ConvBlock(layout=squeeze_layout, units=units, activations=activations, inputs=inputs)

    def forward(self, x):
        ones = [1] * get_num_dims(x)
        x = self.layer(x)
        return x.view(x.size(0), -1, *ones)

class SideBlock(nn.Module):
    """ Add side branch to a :class:`~.layers.ConvBlock`. """
    def __init__(self, inputs=None, **kwargs):
        from .conv_block import ConvBlock # can't be imported in the file beginning due to recursive imports
        super().__init__()
        self.layer = ConvBlock(inputs=inputs, **kwargs)

    def forward(self, x):
        return self.layer(x)

class Combine(nn.Module):
    """ Combine list of tensor into one.

    Parameters
    ----------
    inputs : sequence of torch.Tensors
        Tensors to combine.

    op : str or callable
        If callable, then operation to be applied to the list of inputs.
        If 'concat', 'cat', '.', then inputs are concated along channels axis.
        If 'sum', '+', then inputs are summed.
        If 'mul', '*', then inputs are multiplied.
        If 'avg', then inputs are averaged.
        If 'softsum', '&', then every tensor is passed through 1x1 convolution in order to have
        the same number of channels as the first tensor, and then summed.
    """
    @staticmethod
    def concat(inputs):
        return torch.cat(inputs, dim=1)

    @staticmethod
    def sum(inputs):
        return torch.stack(inputs, dim=0).sum(dim=0)

    @staticmethod
    def mul(inputs):
        """ Multiplication. """
        result = 1
        for item in inputs:
            result = result * item
        return result

    @staticmethod
    def mean(inputs):
        return torch.mean(inputs)

    @staticmethod
    def softsum(self, inputs):
        """ Softsum. """
        #pylint: disable=bad-staticmethod-argument
        inputs = [conv(tensor) for conv, tensor in zip(self.conv, inputs)]
        return torch.stack(inputs, dim=0).sum(dim=0)

    OPS = {
        concat.__func__: ['concat', 'cat', '.'],
        sum.__func__: ['sum', 'plus', '+'],
        mul.__func__: ['multi', 'mul', '*'],
        mean.__func__: ['average', 'avg', 'mean'],
        softsum.__func__: ['softsum', '&'],
    }

    OPS = {alias: method for method, aliases in OPS.items() for alias in aliases}
    ALL_OPS = list(OPS.keys())

    def __init__(self, inputs=None, op='concat', force_resize=True):
        from .conv_block import ConvBlock # can't be imported in the file beginning due to recursive imports
        super().__init__()

        self.force_resize = force_resize
        self.op = op
        if op in self.OPS and self.OPS[op].__name__ == 'softsum':
            args = dict(layout='c', filters=get_shape(inputs[0])[1],
                        kernel_size=1)
            conv = [ConvBlock(inputs=tensor, **args) for tensor in inputs]
            self.conv = nn.ModuleList(conv)
            self.op = lambda inputs: self.OPS[op](self, inputs)

    def spatial_resize(self, inputs):
        """ Force the same shapes of the inputs, if needed. """
        shape_ = get_shape(inputs[0])
        dim_ = get_num_dims(inputs[0])
        spatial_shape_ = shape_[-dim_:]

        resized = []
        for item in inputs:
            shape = get_shape(item)
            dim = get_num_dims(item)
            spatial_shape = shape[-dim:]
            if dim > 0 and spatial_shape_ != tuple([1]*dim) and spatial_shape != spatial_shape_:
                item = Crop(inputs[0])(item)
            resized.append(item)
        return resized

    def forward(self, inputs):
        if self.force_resize:
            inputs = self.spatial_resize(inputs)
        if callable(self.op):
            return self.op(inputs)
        if self.op in self.OPS:
            return self.OPS[self.op](inputs)
        raise ValueError('Combine operation must be a callable or \
                          one from {}, instead got {}.'.format(self.ALL_OPS, self.op))

    def extra_repr(self):
        if isinstance(self.op, str):
            return 'op=' + self.op
        return 'op=' + 'callable ' + self.op.__name__
<|endoftext|>


<commit_before># Copyright (c) 2009-2016 The Regents of the University of Michigan
# This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.

""" Compute properties of hard particle configurations.
"""

from __future__ import print_function

from hoomd import _hoomd
from hoomd.hpmc import _hpmc
from hoomd.hpmc import integrate
from hoomd.compute import _compute
import hoomd

class free_volume(_compute):
    R""" Compute the free volume available to a test particle by stochastic integration.

    Args:
        mc (:py:mod:`hoomd.hpmc.integrate`): MC integrator.
        seed (int): Random seed for MC integration.
        type (str): Type of particle to use for integration
        nsample (int): Number of samples to use in MC integration
        suffix (str): Suffix to use for log quantity

    :py:class`free_volume` computes the free volume of a particle assembly using stochastic integration with a test particle type.
    It works together with an HPMC integrator, which defines the particle types used in the simulation.
    As parameters it requires the number of MC integration samples (*nsample*), and the type of particle (*test_type*)
    to use for the integration.

    Once initialized, the compute provides a log quantity
    called **hpmc_free_volume**, that can be logged via :py:class:`hoomd.analyze.log`.
    If a suffix is specified, the log quantities name will be
    **hpmc_free_volume_suffix**.

    Examples::

        mc = hpmc.integrate.sphere(seed=415236)
        compute.free_volume(mc=mc, seed=123, test_type='B', nsample=1000)
        log = analyze.log(quantities=['hpmc_free_volume'], period=100, filename='log.dat', overwrite=True)

    """
    def __init__(self, mc, seed, suffix='', test_type=None, nsample=None):
        hoomd.util.print_status_line();

        # initialize base class
        _compute.__init__(self);

        # create the c++ mirror class
        cl = _hoomd.CellList(hoomd.context.current.system_definition);
        hoomd.context.current.system.addCompute(cl, "auto_cl3")

        cls = None;
        if not hoomd.context.exec_conf.isCUDAEnabled():
            if isinstance(mc, integrate.sphere):
                cls = _hpmc.ComputeFreeVolumeSphere;
            elif isinstance(mc, integrate.convex_polygon):
                cls = _hpmc.ComputeFreeVolumeConvexPolygon;
            elif isinstance(mc, integrate.simple_polygon):
                cls = _hpmc.ComputeFreeVolumeSimplePolygon;
            elif isinstance(mc, integrate.convex_polyhedron):
                cls = integrate._get_sized_entry('ComputeFreeVolumeConvexPolyhedron', mc.max_verts);
            elif isinstance(mc, integrate.convex_spheropolyhedron):
                cls = integrate._get_sized_entry('ComputeFreeVolumeSpheropolyhedron', mc.max_verts);
            elif isinstance(mc, integrate.ellipsoid):
                cls = _hpmc.ComputeFreeVolumeEllipsoid;
            elif isinstance(mc, integrate.convex_spheropolygon):
                cls =_hpmc.ComputeFreeVolumeSpheropolygon;
            elif isinstance(mc, integrate.faceted_sphere):
                cls =_hpmc.ComputeFreeVolumeFacetedSphere;
            elif isinstance(mc, integrate.polyhedron):
                cls =_hpmc.ComputeFreeVolumePolyhedron;
            elif isinstance(mc, integrate.sphinx):
                cls =_hpmc.ComputeFreeVolumeSphinx;
            elif isinstance(mc, integrate.sphere_union):
                cls = _hpmc.ComputeFreeVolumeSphereUnion
            else:
                hoomd.context.msg.error("compute.free_volume: Unsupported integrator.\n");
                raise RuntimeError("Error initializing compute.free_volume");
        else:
            if isinstance(mc, integrate.sphere):
                cls = _hpmc.ComputeFreeVolumeGPUSphere;
            elif isinstance(mc, integrate.convex_polygon):
                cls = _hpmc.ComputeFreeVolumeGPUConvexPolygon;
            elif isinstance(mc, integrate.simple_polygon):
                cls = _hpmc.ComputeFreeVolumeGPUSimplePolygon;
            elif isinstance(mc, integrate.convex_polyhedron):
                cls = integrate._get_sized_entry('ComputeFreeVolumeGPUConvexPolyhedron', mc.max_verts);
            elif isinstance(mc, integrate.convex_spheropolyhedron):
                cls = integrate._get_sized_entry('ComputeFreeVolumeGPUSpheropolyhedron',mc.max_verts);
            elif isinstance(mc, integrate.ellipsoid):
                cls = _hpmc.ComputeFreeVolumeGPUEllipsoid;
            elif isinstance(mc, integrate.convex_spheropolygon):
                cls =_hpmc.ComputeFreeVolumeGPUSpheropolygon;
            elif isinstance(mc, integrate.faceted_sphere):
                cls =_hpmc.ComputeFreeVolumeGPUFacetedSphere;
            elif isinstance(mc, integrate.polyhedron):
                cls =_hpmc.ComputeFreeVolumeGPUPolyhedron;
            elif isinstance(mc, integrate.sphinx):
                cls =_hpmc.ComputeFreeVolumeGPUSphinx;
            elif isinstance(mc, integrate.sphere_union):
                cls = _hpmc.ComputeFreeVolumeGPUSphereUnion
            else:
                hoomd.context.msg.error("compute.free_volume: Unsupported integrator.\n");
                raise RuntimeError("Error initializing compute.free_volume");

        if suffix is not '':
            suffix = '_' + suffix

        self.cpp_compute = cls(hoomd.context.current.system_definition,
                                mc.cpp_integrator,
                                cl,
                                seed,
                                suffix)

        if test_type is not None:
            itype = hoomd.context.current.system_definition.getParticleData().getTypeByName(test_type)
            self.cpp_compute.setTestParticleType(itype)
        if nsample is not None:
            self.cpp_compute.setNumSamples(int(nsample))

        hoomd.context.current.system.addCompute(self.cpp_compute, self.compute_name)
        self.enabled = True
<commit_msg>Revert "enable new sphere union in compute.free_volume()"<commit_after># Copyright (c) 2009-2016 The Regents of the University of Michigan
# This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.

""" Compute properties of hard particle configurations.
"""

from __future__ import print_function

from hoomd import _hoomd
from hoomd.hpmc import _hpmc
from hoomd.hpmc import integrate
from hoomd.compute import _compute
import hoomd

class free_volume(_compute):
    R""" Compute the free volume available to a test particle by stochastic integration.

    Args:
        mc (:py:mod:`hoomd.hpmc.integrate`): MC integrator.
        seed (int): Random seed for MC integration.
        type (str): Type of particle to use for integration
        nsample (int): Number of samples to use in MC integration
        suffix (str): Suffix to use for log quantity

    :py:class`free_volume` computes the free volume of a particle assembly using stochastic integration with a test particle type.
    It works together with an HPMC integrator, which defines the particle types used in the simulation.
    As parameters it requires the number of MC integration samples (*nsample*), and the type of particle (*test_type*)
    to use for the integration.

    Once initialized, the compute provides a log quantity
    called **hpmc_free_volume**, that can be logged via :py:class:`hoomd.analyze.log`.
    If a suffix is specified, the log quantities name will be
    **hpmc_free_volume_suffix**.

    Examples::

        mc = hpmc.integrate.sphere(seed=415236)
        compute.free_volume(mc=mc, seed=123, test_type='B', nsample=1000)
        log = analyze.log(quantities=['hpmc_free_volume'], period=100, filename='log.dat', overwrite=True)

    """
    def __init__(self, mc, seed, suffix='', test_type=None, nsample=None):
        hoomd.util.print_status_line();

        # initialize base class
        _compute.__init__(self);

        # create the c++ mirror class
        cl = _hoomd.CellList(hoomd.context.current.system_definition);
        hoomd.context.current.system.addCompute(cl, "auto_cl3")

        cls = None;
        if not hoomd.context.exec_conf.isCUDAEnabled():
            if isinstance(mc, integrate.sphere):
                cls = _hpmc.ComputeFreeVolumeSphere;
            elif isinstance(mc, integrate.convex_polygon):
                cls = _hpmc.ComputeFreeVolumeConvexPolygon;
            elif isinstance(mc, integrate.simple_polygon):
                cls = _hpmc.ComputeFreeVolumeSimplePolygon;
            elif isinstance(mc, integrate.convex_polyhedron):
                cls = integrate._get_sized_entry('ComputeFreeVolumeConvexPolyhedron', mc.max_verts);
            elif isinstance(mc, integrate.convex_spheropolyhedron):
                cls = integrate._get_sized_entry('ComputeFreeVolumeSpheropolyhedron', mc.max_verts);
            elif isinstance(mc, integrate.ellipsoid):
                cls = _hpmc.ComputeFreeVolumeEllipsoid;
            elif isinstance(mc, integrate.convex_spheropolygon):
                cls =_hpmc.ComputeFreeVolumeSpheropolygon;
            elif isinstance(mc, integrate.faceted_sphere):
                cls =_hpmc.ComputeFreeVolumeFacetedSphere;
            elif isinstance(mc, integrate.polyhedron):
                cls =_hpmc.ComputeFreeVolumePolyhedron;
            elif isinstance(mc, integrate.sphinx):
                cls =_hpmc.ComputeFreeVolumeSphinx;
            elif isinstance(mc, integrate.sphere_union):
                cls = integrate._get_sized_entry('ComputeFreeVolumeSphereUnion', mc.max_members);
            else:
                hoomd.context.msg.error("compute.free_volume: Unsupported integrator.\n");
                raise RuntimeError("Error initializing compute.free_volume");
        else:
            if isinstance(mc, integrate.sphere):
                cls = _hpmc.ComputeFreeVolumeGPUSphere;
            elif isinstance(mc, integrate.convex_polygon):
                cls = _hpmc.ComputeFreeVolumeGPUConvexPolygon;
            elif isinstance(mc, integrate.simple_polygon):
                cls = _hpmc.ComputeFreeVolumeGPUSimplePolygon;
            elif isinstance(mc, integrate.convex_polyhedron):
                cls = integrate._get_sized_entry('ComputeFreeVolumeGPUConvexPolyhedron', mc.max_verts);
            elif isinstance(mc, integrate.convex_spheropolyhedron):
                cls = integrate._get_sized_entry('ComputeFreeVolumeGPUSpheropolyhedron',mc.max_verts);
            elif isinstance(mc, integrate.ellipsoid):
                cls = _hpmc.ComputeFreeVolumeGPUEllipsoid;
            elif isinstance(mc, integrate.convex_spheropolygon):
                cls =_hpmc.ComputeFreeVolumeGPUSpheropolygon;
            elif isinstance(mc, integrate.faceted_sphere):
                cls =_hpmc.ComputeFreeVolumeGPUFacetedSphere;
            elif isinstance(mc, integrate.polyhedron):
                cls =_hpmc.ComputeFreeVolumeGPUPolyhedron;
            elif isinstance(mc, integrate.sphinx):
                cls =_hpmc.ComputeFreeVolumeGPUSphinx;
            elif isinstance(mc, integrate.sphere_union):
                cls = integrate._get_sized_entry('ComputeFreeVolumeGPUSphereUnion', mc.max_members);
            else:
                hoomd.context.msg.error("compute.free_volume: Unsupported integrator.\n");
                raise RuntimeError("Error initializing compute.free_volume");

        if suffix is not '':
            suffix = '_' + suffix

        self.cpp_compute = cls(hoomd.context.current.system_definition,
                                mc.cpp_integrator,
                                cl,
                                seed,
                                suffix)

        if test_type is not None:
            itype = hoomd.context.current.system_definition.getParticleData().getTypeByName(test_type)
            self.cpp_compute.setTestParticleType(itype)
        if nsample is not None:
            self.cpp_compute.setNumSamples(int(nsample))

        hoomd.context.current.system.addCompute(self.cpp_compute, self.compute_name)
        self.enabled = True
<|endoftext|>


<commit_before>import numpy as np
from abc import ABCMeta
from sklearn.externals.six import with_metaclass
from sklearn.utils.validation import _num_samples
import pandas as pd

class GrowingWindow(with_metaclass(ABCMeta)):
    """Growing Window cross validator

    Provides train/test indices to split data in train/test sets.
    Divides the data in n_folds+1 slices.
    For split i [1..n_folds], slices [0..i} are train, slice i is test

    Parameters:
        n_folds : int, default=3
            Number of folds. Must be at least 1
    """

    def __init__(self, n_folds=3):
        self.n_folds = n_folds

    def __repr__(self):
        return _build_repr(self)

    def split(self, X, y=None, labels=None):
        """Generate indices to split data into training and test set.
        Parameters
        ----------
        X : array-like, shape (n_samples, n_features)
            Training data, where n_samples is the number of samples
            and n_features is the number of features.
        y : array-like, of length n_samples
            The target variable for supervised learning problems.
            ignored
        labels : array-like, with shape (n_samples,), optional
            Group labels for the samples used while splitting the dataset into
            train/test set.
            ignored
        Returns
        -------
        train : ndarray
            The training set indices for that split.
        test : ndarray
            The testing set indices for that split.
        """
        n = _num_samples(X)
        n_slices = self.n_folds + 1
        # loop from the first 2 folds to the total number of folds
        for i in range(2, n_slices + 1):
            # the split is the percentage at which to split the folds into train
            # and test. For example when i = 2 we are taking the first 2 folds out
            # of the total available. In this specific case we have to split the
            # two of them in half (train on the first, test on the second),
            # so split = 1/2 = 0.5 = 50%. When i = 3 we are taking the first 3 folds
            # out of the total available, meaning that we have to split the three of them
            # in two at split = 2/3 = 0.66 = 66% (train on the first 2 and test on the
            # following)
            split = float(i - 1) / i
            # as we loop over the folds X and y are updated and increase in size.
            # This is the data that is going to be split and it increases in size
            # in the loop as we account for more folds. If k = 300, with i starting from 2
            # the result is the following in the loop
            # i = 2
            # X = X_train[:(600)]
            # y = y_train[:(600)]
            #
            # i = 3
            # X = X_train[:(900)]
            # y = y_train[:(900)]
            # ....
            n_sub = int(np.floor(float(n * i) / n_slices))
            subset = range(0, n_sub)
            # X and y contain both the folds to train and the fold to test.
            # index is the integer telling us where to split, according to the
            # split percentage we have set above
            n_train = int(np.floor(n_sub * split))
            train_index = np.arange(0, n_train)
            test_index = np.arange(n_train, n_sub)
            yield train_index, test_index

    def get_n_splits(self, X, y=None, labels=None):
        """Returns the number of splitting iterations in the cross-validator
        Parameters
        ----------
        X : array-like, shape (n_samples, n_features)
            Training data, where n_samples is the number of samples
            and n_features is the number of features.
        y : object
            Always ignored, exists for compatibility.
        labels : object
            Always ignored, exists for compatibility.
        Returns
        -------
        n_splits : int
            Returns the number of splitting iterations in the cross-validator.
        """
        if X is None:
            raise ValueError("The X parameter should not be None")
        return self.n_folds

class IntervalGrowingWindow(with_metaclass(ABCMeta)):
    """Growing Window cross-validator based on time intervals"""

    def __init__(self, test_start_date, timestamps='index', test_end_date=None,
                 test_size='1M', train_size=None):

        self.test_start_date = pd.to_datetime(test_start_date)
        self.test_end_date = pd.to_datetime(test_end_date)
        self.test_size = pd.to_timedelta(test_size)
        self.train_size = pd.to_timedelta(train_size)
        self.n_folds = None

        self.timestamps = timestamps
        if timestamps is not 'index':
            self.timestamps = pd.to_datetime(timestamps)

    def generate_intervals(self, timestamps):

        # infer test interval end date if not specified
        # has to be done here to work with timestamps from DataFrame index
        # NOTE: test_end_date is NOT included
        if self.test_end_date is None:
            # can be overridden for reuse
            self.test_end_date = max(timestamps)

        # determine start date of the test intervals
        intervals_start = pd.to_datetime(pd.date_range(self.test_start_date,
                                                       self.test_end_date,
                                                       freq=self.test_size)
                                         .values)

        # convert to (start, end) tuples
        intervals = zip(intervals_start[:-1], intervals_start[1:])

        return intervals

    def split(self, X, y=None, labels=None):
        """Generate indices to split data into training and test sets based on time stamps"""

        # extract timestamps from DataFrame index, if needed
        timestamps = self.timestamps
        if timestamps is 'index':
            timestamps = pd.to_datetime(X.index.values)

        intervals = self.generate_intervals(timestamps)

        # extract first sample for unlimited train size
        first_sample_date = min(timestamps)

        # number of samples
        n = _num_samples(X)

        # list of indices, to convert booleans later on
        index = np.arange(n)

        # loop over each interval
        for test_start, test_end in intervals:

            if self.train_size is not None:
                train_start = test_start - self.train_size
            else:
                train_start = first_sample_date

            train_interval_bool = np.array(map(lambda date:
                                               train_start <= date < test_start,
                                               timestamps))

            test_interval_bool = np.array(map(lambda date:
                                              test_start <= date < test_end,
                                              timestamps))

            # convert boolean to integer indices
            train_index = index[train_interval_bool]
            test_index = index[test_interval_bool]

            yield train_index, test_index

    def get_n_splits(self, X, y=None, labels=None):
        if X is None:
            raise ValueError("The X parameter should not be None")

        # extract timestamps from DataFrame index, if needed
        timestamps = self.timestamps
        if timestamps is 'index':
            timestamps = pd.to_datetime(X.index.values)

        intervals = self.generate_intervals(timestamps)

        # compute number of folds
        self.n_folds = len(intervals)

        return self.n_folds
<commit_msg>set default test size to 30 days instead of 1 minute :-S<commit_after>import numpy as np
from abc import ABCMeta
from sklearn.externals.six import with_metaclass
from sklearn.utils.validation import _num_samples
import pandas as pd

class GrowingWindow(with_metaclass(ABCMeta)):
    """Growing Window cross validator

    Provides train/test indices to split data in train/test sets.
    Divides the data in n_folds+1 slices.
    For split i [1..n_folds], slices [0..i} are train, slice i is test

    Parameters:
        n_folds : int, default=3
            Number of folds. Must be at least 1
    """

    def __init__(self, n_folds=3):
        self.n_folds = n_folds

    def __repr__(self):
        return _build_repr(self)

    def split(self, X, y=None, labels=None):
        """Generate indices to split data into training and test set.
        Parameters
        ----------
        X : array-like, shape (n_samples, n_features)
            Training data, where n_samples is the number of samples
            and n_features is the number of features.
        y : array-like, of length n_samples
            The target variable for supervised learning problems.
            ignored
        labels : array-like, with shape (n_samples,), optional
            Group labels for the samples used while splitting the dataset into
            train/test set.
            ignored
        Returns
        -------
        train : ndarray
            The training set indices for that split.
        test : ndarray
            The testing set indices for that split.
        """
        n = _num_samples(X)
        n_slices = self.n_folds + 1
        # loop from the first 2 folds to the total number of folds
        for i in range(2, n_slices + 1):
            # the split is the percentage at which to split the folds into train
            # and test. For example when i = 2 we are taking the first 2 folds out
            # of the total available. In this specific case we have to split the
            # two of them in half (train on the first, test on the second),
            # so split = 1/2 = 0.5 = 50%. When i = 3 we are taking the first 3 folds
            # out of the total available, meaning that we have to split the three of them
            # in two at split = 2/3 = 0.66 = 66% (train on the first 2 and test on the
            # following)
            split = float(i - 1) / i
            # as we loop over the folds X and y are updated and increase in size.
            # This is the data that is going to be split and it increases in size
            # in the loop as we account for more folds. If k = 300, with i starting from 2
            # the result is the following in the loop
            # i = 2
            # X = X_train[:(600)]
            # y = y_train[:(600)]
            #
            # i = 3
            # X = X_train[:(900)]
            # y = y_train[:(900)]
            # ....
            n_sub = int(np.floor(float(n * i) / n_slices))
            subset = range(0, n_sub)
            # X and y contain both the folds to train and the fold to test.
            # index is the integer telling us where to split, according to the
            # split percentage we have set above
            n_train = int(np.floor(n_sub * split))
            train_index = np.arange(0, n_train)
            test_index = np.arange(n_train, n_sub)
            yield train_index, test_index

    def get_n_splits(self, X, y=None, labels=None):
        """Returns the number of splitting iterations in the cross-validator
        Parameters
        ----------
        X : array-like, shape (n_samples, n_features)
            Training data, where n_samples is the number of samples
            and n_features is the number of features.
        y : object
            Always ignored, exists for compatibility.
        labels : object
            Always ignored, exists for compatibility.
        Returns
        -------
        n_splits : int
            Returns the number of splitting iterations in the cross-validator.
        """
        if X is None:
            raise ValueError("The X parameter should not be None")
        return self.n_folds

class IntervalGrowingWindow(with_metaclass(ABCMeta)):
    """Growing Window cross-validator based on time intervals"""

    def __init__(self, test_start_date, timestamps='index', test_end_date=None,
                 test_size='30 days', train_size=None):

        self.test_start_date = pd.to_datetime(test_start_date)
        self.test_end_date = pd.to_datetime(test_end_date)
        self.test_size = pd.to_timedelta(test_size)
        self.train_size = pd.to_timedelta(train_size)
        self.n_folds = None

        self.timestamps = timestamps
        if timestamps is not 'index':
            self.timestamps = pd.to_datetime(timestamps)

    def generate_intervals(self, timestamps):

        # infer test interval end date if not specified
        # has to be done here to work with timestamps from DataFrame index
        # NOTE: test_end_date is NOT included
        if self.test_end_date is None:
            # can be overridden for reuse
            self.test_end_date = max(timestamps)

        # determine start date of the test intervals
        intervals_start = pd.to_datetime(pd.date_range(self.test_start_date,
                                                       self.test_end_date,
                                                       freq=self.test_size)
                                         .values)

        # convert to (start, end) tuples
        intervals = zip(intervals_start[:-1], intervals_start[1:])

        return intervals

    def split(self, X, y=None, labels=None):
        """Generate indices to split data into training and test sets based on time stamps"""

        # extract timestamps from DataFrame index, if needed
        timestamps = self.timestamps
        if timestamps is 'index':
            timestamps = pd.to_datetime(X.index.values)

        intervals = self.generate_intervals(timestamps)

        # extract first sample for unlimited train size
        first_sample_date = min(timestamps)

        # number of samples
        n = _num_samples(X)

        # list of indices, to convert booleans later on
        index = np.arange(n)

        # loop over each interval
        for test_start, test_end in intervals:

            if self.train_size is not None:
                train_start = test_start - self.train_size
            else:
                train_start = first_sample_date

            train_interval_bool = np.array(map(lambda date:
                                               train_start <= date < test_start,
                                               timestamps))

            test_interval_bool = np.array(map(lambda date:
                                              test_start <= date < test_end,
                                              timestamps))

            # convert boolean to integer indices
            train_index = index[train_interval_bool]
            test_index = index[test_interval_bool]

            yield train_index, test_index

    def get_n_splits(self, X, y=None, labels=None):
        if X is None:
            raise ValueError("The X parameter should not be None")

        # extract timestamps from DataFrame index, if needed
        timestamps = self.timestamps
        if timestamps is 'index':
            timestamps = pd.to_datetime(X.index.values)

        intervals = self.generate_intervals(timestamps)

        # compute number of folds
        self.n_folds = len(intervals)

        return self.n_folds
<|endoftext|>


<commit_before>"""
Remove 'benchbuild_events' from the managed part of the schema.

We do not delete this table during our upgrades,
because we do not want to wipe measurement data.

During downgrade we will make sure to create the table as needed.
"""
from sqlalchemy import (MetaData, SmallInteger, BigInteger, Numeric, Table,
                        Column, ForeignKey, Integer, String)
from benchbuild.utils.schema import Run, RunGroup, Project, Experiment

META = MetaData()

# yapf: disable
EVENTS = Table('benchbuild_events', META,
               Column('name', String, index=True),
               Column('start', Numeric, primary_key=True),
               Column('duration', Numeric),
               Column('id', Integer),
               Column('type', SmallInteger),
               Column('tid', BigInteger),
               Column('run_id', Integer,
                      ForeignKey('run.id', onupdate='CASCADE', ondelete='CASCADE'),
                      nullable=False, index=True, primary_key=True),
               extend_existing=True)
# yapf: enable

def upgrade(migrate_engine):
    pass

def downgrade(migrate_engine):
    META.bind = migrate_engine
    EVENTS.create(checkfirst=True)
<commit_msg>utils/schema: yapf<commit_after>"""
Remove 'benchbuild_events' from the managed part of the schema.

We do not delete this table during our upgrades,
because we do not want to wipe measurement data.

During downgrade we will make sure to create the table as needed.
"""
from sqlalchemy import (MetaData, SmallInteger, BigInteger, Numeric, Table,
                        Column, ForeignKey, Integer, String)
from benchbuild.utils.schema import Run, RunGroup, Project, Experiment

META = MetaData()

# yapf: disable
EVENTS = Table('benchbuild_events', META,
               Column('name', String, index=True),
               Column('start', Numeric, primary_key=True),
               Column('duration', Numeric),
               Column('id', Integer),
               Column('type', SmallInteger),
               Column('tid', BigInteger),
               Column('run_id', Integer,
                      ForeignKey('run.id',
                                 onupdate='CASCADE', ondelete='CASCADE'),
                      nullable=False, index=True, primary_key=True),
               extend_existing=True)
# yapf: enable

def upgrade(migrate_engine):
    pass

def downgrade(migrate_engine):
    META.bind = migrate_engine
    EVENTS.create(checkfirst=True)
<|endoftext|>


<commit_before>from django.contrib import admin
from django.conf.urls.defaults import patterns, include, url
from django.views.generic import ListView, DetailView

from karmaworld.apps.courses.models import Course
from karmaworld.apps.courses.views import CourseDetailView

# See: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#hooking-adminsite-instances-into-your-urlconf
admin.autodiscover()

# See: https://docs.djangoproject.com/en/dev/topics/http/urls/
urlpatterns = patterns('',
    # Admin panel and documentation:
    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
    url(r'^admin/', include(admin.site.urls)),

    #url(r'^/(?P<school_slug>[^/]+)/(?P<slug>[^/]+)$',
    #url(r'^/[a-z0-9\-]+$', CourseDetailView.as_view(), name='course_detail'),
    url(r'^(?P<slug>[^/]+)$', CourseDetailView.as_view(), name='course_detail'),

    url(r'^$', ListView.as_view(model=Course), name='home'),
)
<commit_msg>route courses through /school_slug/course_slug/ instead of /course_slug<commit_after>from django.contrib import admin
from django.conf.urls.defaults import patterns, include, url
from django.views.generic import ListView, DetailView

from karmaworld.apps.courses.models import Course
from karmaworld.apps.courses.views import CourseDetailView

# See: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#hooking-adminsite-instances-into-your-urlconf
admin.autodiscover()

# See: https://docs.djangoproject.com/en/dev/topics/http/urls/
urlpatterns = patterns('',
    # Admin panel and documentation:
    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
    url(r'^admin/', include(admin.site.urls)),

    #url(r'^/(?P<school_slug>[^/]+)/(?P<slug>[^/]+)$',
    #url(r'^/[a-z0-9\-]+$', CourseDetailView.as_view(), name='course_detail'),
    url(r'^(?P<school_slug>[^/]+)/(?P<slug>[^/]+)$', CourseDetailView.as_view(), name='course_detail'),

    url(r'^$', ListView.as_view(model=Course), name='home'),
)
<|endoftext|>


<commit_before>import numpy
import sympy

from ..helpers import article, get_all_exponents, prod
from ._helpers import NSimplexScheme

citation = article(
    authors=["P. Silvester"],
    title="Symmetric quadrature formulae for simplexes",
    journal="Math. Comp.",
    volume="24",
    pages="95-100",
    year="1970",
    url="https://doi.org/10.1090/S0025-5718-1970-0258283-6",
)

# frac(prod([math.factorial(l) for l in m]), math.factorial(sum(m) + dim))
def integrate_bary_over_unit_simplex(k, symbolic):
    # This is very similar to integrate_monomial_over_unit_simplex, except that n =
    # len(k) - 1, not len(k). This is because we're integrating over a polynomial in
    # barycentric coordinates here. Also the integration for [0, ..., 0] is set equal to
    # 1. This ensure that the weights add up to 1, not the volume of the unit simplex.
    frac = sympy.Rational if symbolic else lambda a, b: a / b

    n = len(k) - 1
    assert all(kk >= 0 for kk in k)

    if all(kk == 0 for kk in k):
        # return frac(1, math.factorial(n))
        return 1

    # find first nonzero
    idx = next((i for i, j in enumerate(k) if j > 0), None)
    alpha = frac(k[idx], sum(k) + n)
    k2 = k.copy()
    k2[idx] -= 1
    return integrate_bary_over_unit_simplex(k2, symbolic) * alpha

def _newton_cotes(dim, n, point_fun, symbolic):
    degree = n

    # points
    idxs = numpy.array(get_all_exponents(dim + 1, n)[-1])
    points = point_fun(idxs)

    # weights
    if n == 0:
        weights = numpy.array([1])
        return points, weights, degree

    weights = numpy.empty(len(points))
    kk = 0
    for idx in idxs:
        # Define the polynomial which to integrate over the simplex.
        t = sympy.DeferredVector("t")
        g = prod(
            sympy.poly((t[i] - point_fun(k)) / (point_fun(m) - point_fun(k)))
            for i, m in enumerate(idx)
            for k in range(m)
        )
        # make sure the exponents are all of the correct length
        exp = [list(m) + [0] * (dim - len(m) + 1) for m in g.monoms()]
        weights[kk] = sum(
            c * integrate_bary_over_unit_simplex(m, symbolic)
            for m, c in zip(exp, g.coeffs())
        )
        kk += 1

    return weights, points, degree

def silvester(dim, variant, n, symbolic=False):
    frac = numpy.vectorize(sympy.Rational) if symbolic else lambda a, b: a / b

    if variant == "closed":
        weights, points, degree = _newton_cotes(dim, n, lambda k: frac(k, n), symbolic)
    else:
        assert variant == "open"
        weights, points, degree = _newton_cotes(
            dim, n, lambda k: frac(k + 1, n + 1 + dim), symbolic
        )
        if n == 0:
            degree = 1

    return NSimplexScheme(
        f"Silvester ({variant}, {n})", dim, weights, points, degree, citation
    )
<commit_msg>more silvester simplification<commit_after>import numpy
import sympy

from ..helpers import article, get_all_exponents, prod
from ._helpers import NSimplexScheme

citation = article(
    authors=["P. Silvester"],
    title="Symmetric quadrature formulae for simplexes",
    journal="Math. Comp.",
    volume="24",
    pages="95-100",
    year="1970",
    url="https://doi.org/10.1090/S0025-5718-1970-0258283-6",
)

# frac(prod([math.factorial(l) for l in m]), math.factorial(sum(m) + dim))
def integrate_bary(k, symbolic):
    # This is very similar to integrate_monomial_over_unit_simplex, except that n =
    # len(k) - 1, not len(k). This is because we're integrating over a polynomial in
    # barycentric coordinates here. Also the integration for [0, ..., 0] is set equal to
    # 1. This ensure that the weights add up to 1, not the volume of the unit simplex.
    frac = sympy.Rational if symbolic else lambda a, b: a / b

    n = len(k) - 1
    assert all(kk >= 0 for kk in k)

    if all(kk == 0 for kk in k):
        # return frac(1, math.factorial(n))
        return 1

    # find first nonzero
    idx = next((i for i, j in enumerate(k) if j > 0), None)
    alpha = frac(k[idx], sum(k) + n)
    k2 = k.copy()
    k2[idx] -= 1
    return integrate_bary(k2, symbolic) * alpha

def _get_data(dim, n, point_fun, symbolic):
    # points
    idxs = numpy.array(get_all_exponents(dim + 1, n)[-1])
    points = point_fun(idxs)

    # weights
    weights = numpy.empty(len(points))
    kk = 0
    for idx in idxs:
        # Define the polynomial which to integrate over the simplex.
        t = sympy.DeferredVector("t")
        g = prod(
            sympy.poly((t[i] - point_fun(k)) / (point_fun(m) - point_fun(k)))
            for i, m in enumerate(idx)
            for k in range(m)
        )
        if isinstance(g, int):
            exp = [0] * (dim + 1)
            coeffs = g
        else:
            # make sure the exponents are all of the correct length
            exp = [list(m) + [0] * (dim - len(m) + 1) for m in g.monoms()]
            coeffs = g.coeffs()
        weights[kk] = sum(c * integrate_bary(m, symbolic) for c, m in zip(coeffs, exp))
        kk += 1

    return weights, points

def silvester(dim, variant, n, symbolic=False):
    frac = numpy.vectorize(sympy.Rational) if symbolic else lambda a, b: a / b

    if variant == "closed":
        degree = n

        def points1d(k):
            return frac(k, n)

    else:
        assert variant == "open"
        degree = 1 if n == 0 else n

        def points1d(k):
            return frac(k + 1, n + 1 + dim)

    weights, points = _get_data(dim, n, points1d, symbolic)

    return NSimplexScheme(
        f"Silvester ({variant}, {n})", dim, weights, points, degree, citation
    )
<|endoftext|>