# Goulib¶

library of useful code for scientific + technical applications

• author: Philippe Guglielmetti [email protected]

• installation : "pip install Goulib"

• distribution: https://pypi.python.org/pypi/Goulib
• 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)