Goulib

library of useful code for scientific + technical applications

  • author: Philippe Guglielmetti [email protected]
  • copyright: Copyright 2013 Philippe Guglielmetti
  • license: LGPL (see LICENSE.TXT)

  • installation : "pip install Goulib"

  • distribution: https://pypi.python.org/pypi/Goulib
  • documentation: https://goulib.readthedocs.org/
  • source : https://github.com/goulu/Goulib

Some modules offer specific IPython Notebook support

In [1]:
from Goulib.notebook import *
h2('Notebook')
h4('some useful tools for IPYthon/Jupyter notebooks')
h('notably a "print" function which accepts',1,1+1,int(9**.5),'or even more parameters')
print([1,2,3],('a','b','c'))

Notebook

some useful tools for IPYthon/Jupyter notebooks

notably a "print" function which accepts 1 2 3 or even more parameters
[1, 2, 3] ('a', 'b', 'c')
In [2]:
from Goulib import math2, itertools2 #Goulib modules that complement std modules

Modules

  • Math2 more math without numpy
  • Expr
  • Stats
  • Table "mini pandas.DataFrame" Table class with Excel + CSV I/O, easy access to columns, HTML output, and much more.
  • Geom and Drawing 2D geometry and vector graphics with .DXF, .SVG , .PDF I/O and bitmap graphics output
  • Graph Eulerian graphs based on NetworkX
  • Image image processing made simple
  • Colors color management

Polynomial

a Polynomial is an Expr defined by factors and with some more methods

In [3]:
from Goulib.polynomial import *

p1=Polynomial([-1,1,3]) # inited from coefficients in ascending power order
p1 # Latex output
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
C:\Anaconda\lib\site-packages\IPython\core\formatters.py in __call__(self, obj)
    341             method = _safe_get_formatter_method(obj, self.print_method)
    342             if method is not None:
--> 343                 return method()
    344             return None
    345         else:

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in _repr_html_(self)
    186     def _repr_html_(self):
    187         """default rich format is LaTeX"""
--> 188         return self._repr_latex_()
    189 
    190     def latex(self):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in _repr_latex_(self)
    193 
    194     def _repr_latex_(self):
--> 195         return r'$%s$'%self.latex()
    196 
    197     def _plot(self, ax, x=None, y=None, **kwargs):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in latex(self)
    190     def latex(self):
    191         """:return: string LaTex formula"""
--> 192         return LatexVisitor().visit(self.body)
    193 
    194     def _repr_latex_(self):

C:\Anaconda\lib\ast.py in visit(self, node)
    243         method = 'visit_' + node.__class__.__name__
    244         visitor = getattr(self, method, self.generic_visit)
--> 245         return visitor(node)
    246 
    247     def generic_visit(self, node):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in visit_BinOp(self, n)
    357 
    358     def visit_BinOp(self, n):
--> 359         return self._Bin(n.left,n.op,n.right)
    360 
    361     def visit_Compare(self,n):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in _Bin(self, left, op, right)
    403                 return self._Bin(right,op,left)
    404 
--> 405         l,r = self.visit(left),self.visit(right)
    406 
    407         #handle divisions and power first as precedence doesn't matter

C:\Anaconda\lib\ast.py in visit(self, node)
    243         method = 'visit_' + node.__class__.__name__
    244         visitor = getattr(self, method, self.generic_visit)
--> 245         return visitor(node)
    246 
    247     def generic_visit(self, node):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in visit_BinOp(self, n)
    357 
    358     def visit_BinOp(self, n):
--> 359         return self._Bin(n.left,n.op,n.right)
    360 
    361     def visit_Compare(self,n):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in _Bin(self, left, op, right)
    403                 return self._Bin(right,op,left)
    404 
--> 405         l,r = self.visit(left),self.visit(right)
    406 
    407         #handle divisions and power first as precedence doesn't matter

C:\Anaconda\lib\ast.py in visit(self, node)
    243         method = 'visit_' + node.__class__.__name__
    244         visitor = getattr(self, method, self.generic_visit)
--> 245         return visitor(node)
    246 
    247     def generic_visit(self, node):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in visit_BinOp(self, n)
    357 
    358     def visit_BinOp(self, n):
--> 359         return self._Bin(n.left,n.op,n.right)
    360 
    361     def visit_Compare(self,n):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in _Bin(self, left, op, right)
    403                 return self._Bin(right,op,left)
    404 
--> 405         l,r = self.visit(left),self.visit(right)
    406 
    407         #handle divisions and power first as precedence doesn't matter

C:\Anaconda\lib\ast.py in visit(self, node)
    243         method = 'visit_' + node.__class__.__name__
    244         visitor = getattr(self, method, self.generic_visit)
--> 245         return visitor(node)
    246 
    247     def generic_visit(self, node):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in visit_UnaryOp(self, n)
    395             return r'%s\left(%s\right)' % (operators[type(op)][3], self.visit(n.operand))
    396         else:
--> 397             return r'%s %s' % (operators[type(op)][3], self.visit(n.operand))
    398 
    399     def _Bin(self, left,op,right):

KeyError: <class 'module'>
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
C:\Anaconda\lib\site-packages\IPython\core\formatters.py in __call__(self, obj)
    341             method = _safe_get_formatter_method(obj, self.print_method)
    342             if method is not None:
--> 343                 return method()
    344             return None
    345         else:

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in _repr_latex_(self)
    193 
    194     def _repr_latex_(self):
--> 195         return r'$%s$'%self.latex()
    196 
    197     def _plot(self, ax, x=None, y=None, **kwargs):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in latex(self)
    190     def latex(self):
    191         """:return: string LaTex formula"""
--> 192         return LatexVisitor().visit(self.body)
    193 
    194     def _repr_latex_(self):

C:\Anaconda\lib\ast.py in visit(self, node)
    243         method = 'visit_' + node.__class__.__name__
    244         visitor = getattr(self, method, self.generic_visit)
--> 245         return visitor(node)
    246 
    247     def generic_visit(self, node):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in visit_BinOp(self, n)
    357 
    358     def visit_BinOp(self, n):
--> 359         return self._Bin(n.left,n.op,n.right)
    360 
    361     def visit_Compare(self,n):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in _Bin(self, left, op, right)
    403                 return self._Bin(right,op,left)
    404 
--> 405         l,r = self.visit(left),self.visit(right)
    406 
    407         #handle divisions and power first as precedence doesn't matter

C:\Anaconda\lib\ast.py in visit(self, node)
    243         method = 'visit_' + node.__class__.__name__
    244         visitor = getattr(self, method, self.generic_visit)
--> 245         return visitor(node)
    246 
    247     def generic_visit(self, node):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in visit_BinOp(self, n)
    357 
    358     def visit_BinOp(self, n):
--> 359         return self._Bin(n.left,n.op,n.right)
    360 
    361     def visit_Compare(self,n):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in _Bin(self, left, op, right)
    403                 return self._Bin(right,op,left)
    404 
--> 405         l,r = self.visit(left),self.visit(right)
    406 
    407         #handle divisions and power first as precedence doesn't matter

C:\Anaconda\lib\ast.py in visit(self, node)
    243         method = 'visit_' + node.__class__.__name__
    244         visitor = getattr(self, method, self.generic_visit)
--> 245         return visitor(node)
    246 
    247     def generic_visit(self, node):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in visit_BinOp(self, n)
    357 
    358     def visit_BinOp(self, n):
--> 359         return self._Bin(n.left,n.op,n.right)
    360 
    361     def visit_Compare(self,n):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in _Bin(self, left, op, right)
    403                 return self._Bin(right,op,left)
    404 
--> 405         l,r = self.visit(left),self.visit(right)
    406 
    407         #handle divisions and power first as precedence doesn't matter

C:\Anaconda\lib\ast.py in visit(self, node)
    243         method = 'visit_' + node.__class__.__name__
    244         visitor = getattr(self, method, self.generic_visit)
--> 245         return visitor(node)
    246 
    247     def generic_visit(self, node):

D:\Users\guglie0p\Develop\Python\Goulib\Goulib\expr.py in visit_UnaryOp(self, n)
    395             return r'%s\left(%s\right)' % (operators[type(op)][3], self.visit(n.operand))
    396         else:
--> 397             return r'%s %s' % (operators[type(op)][3], self.visit(n.operand))
    398 
    399     def _Bin(self, left,op,right):

KeyError: <class 'module'>
Out[3]:
In [ ]:
p2=Polynomial('- 5x^3 +3*x') # inited from string, in any power order, with optional spaces and *
p2.plot()
In [ ]:
[(x,p1(x)) for x in itertools2.linspace(-1,1,11)] #evaluation
In [ ]:
p1-p2+2 # addition and subtraction of polynomials and scalars
In [ ]:
-3*p1*p2**2 # polynomial (and scalar) multiplication and scalar power
In [ ]:
p1.derivative()+p2.integral() #integral and derivative

Motion

"motion laws" are functions of time which return (position, velocity, acceleration, jerk) tuples

In [ ]:
from Goulib.motion import *

Polynomial Segments

Polynomials are very handy to define Segments as coefficients can easily be determined from start/end conditions. Also, polynomials can easily be integrated or derivated in order to obtain position, velocity, or acceleration laws from each other.

Motion defines several handy functions that return SegmentPoly matching common situations

In [ ]:
seg=Segment2ndDegree(0,1,(-1,1,2)) # time interval and initial position,velocity and constant acceleration
seg.plot()
In [ ]:
seg=Segment4thDegree(0,None,(-2,1),(2,3)) #start time and initial and final (position,velocity)
seg.plot()
In [ ]:
seg=Segment4thDegree(0,2,(-2,1),(None,3)) # start and final time, initial (pos,vel) and final vel
seg.plot()

Interval

operations on [a..b[ intervals

In [ ]:
from Goulib.interval import *

Interval(5,6)+Interval(2,3)+Interval(3,4)

Piecewise

Piecewise defined functions

In [ ]:
from Goulib.piecewise import *

The simplest are piecewise continuous functions. They are defined by $(x_i,y_i)$ tuples given in any order.

$f(x) = \begin{cases}y_0 & x < x_1 \\ y_i & x_i \le x < x_{i+1} \\ y_n & x > x_n \end{cases}$

In [ ]:
p1=Piecewise([(4,4),(3,3),(1,1),(5,0)])
p1.plot()

By default y0=0 , but it can be specified at construction.

Piecewise functions can also be defined by adding (x0,y,x1) segments

In [ ]:
p2=Piecewise(default=1)
p2+=(2.5,1,6.5)
p2+=(1.5,1,3.5)
p2.plot(xmax=7,ylim=(-1,5))
In [ ]:
plot.plot([p1,p2,p1+p2,p1-p2,p1*p2,p1/p2],
     labels=['p1','p2','p1+p2','p1-p2','p1*p2','p1/p2'],
     xmax=7, ylim=(-2,10), offset=0.02)
In [ ]:
p1=Piecewise([(2,True)],False)
p2=Piecewise([(1,True),(2,False),(3,True)],False)
plot.plot([p1,p2,p1|p2,p1&p2,p1^p2,p1>>3],
     labels=['p1','p2','p1 or p2','p1 and p2','p1 xor p2','p1>>3'],
     xmax=7,ylim=(-.5,1.5), offset=0.02)