How to differentiate within a class? python beginner - python

from sympy.mpmath import *
I'm constructing a beam model, but I've encountered some trouble with the last part - getSlope. Otherwise though, the rest should be fine.
class beam(object):
"""Model of a beam.
"""
def __init__(self, E, I, L):
"""The class costructor.
"""
self.E = E # Young's modulus of the beam in N/m^2
self.I = I # Second moment of area of the beam in m^4
self.L = L # Length of the beam in m
self.Loads = [(0.0, 0.0)] # the list of loads applied to the beam
def setLoads(self, Loads):
'''This function allows multiple point loads to be applied to the beam
using a list of tuples of the form (load, position)
'''
self.Loads = Loads
The above doesn't need any adjustment since it was given.
def beamDeflection(self, Load, x):
"""A measure of how much the beam bends.
"""
a = 2.5
b = a + (x - a)
(P1, A) = Load
if 0 <= x <= a:
v = ((P1*b*x)/(6*self.L*self.E*self.I))*((self.L**2)-(x**2)-(b**2))
else:
if a < x <= 5:
v = ((P1*b)/(6*self.L*self.E*self.I)) * (((self.L/b)*((x-a)**3)) - (x**3) + (x*((self.L**2) - (b**2))))
return v
The above function 'beamDeflection' is some simple hardcoding that I've done, where if a single load is placed on the left hand side, then a certain formula is used and if the load is on the other side, then a different formula is used.
def getTotalDeflection(self, x):
"""A superposition of the deflection.
"""
return sum(self.beamDeflection(loadall, x) for loadall in self.Loads)
'getTotalDeflection' calculates the total deflection at a point when multiple loads are placed on it.
def getSlope(self, x):
"""Differentiate 'v' then input a value for x to obtain a result.
"""
mp.dps = 15
mp.pretty = True
theta = sympy.diff(lambda x: self.beamDeflection(self.Loads, x), x)
return theta
b = beam(8.0E9, 1.333E-4, 5.0)
b.setLoads([(900, 3.1), (700, 3.8), (1000, 4.2)])
print b.getSlope(1.0)
For this function, I'm supposed to differentiate 'beamDeflection' or 'v' as I defined it while it's under more than one load then input a value for x to find the gradient/slope.
I'm following this: "http://docs.sympy.org/dev/modules/mpmath/calculus/differentiation.html" to differentiate, but it needs a second argument (an integer it seems) for it to work, so I don't think this is the correct method of differentiating it. Could anyone shed some light on this please?

Imports
First things first, get in the good habit of not importing things with a star.
Here's a tangible example from the sympy package.
from sympy import * # imports the symbol pi
>>> type(pi) # can be used to construct analytical expressions
<class 'sympy.core.numbers.Pi'>
>>> 2*pi
2*pi
>>> from sympy.mpmath import * # imports a different pi and shadows the previous one
>>> type(pi) # floating point precision of the constant pi
<class 'sympy.mpmath.ctx_mp_python.constant'>
>>> 2*pi
mpf('6.2831853071795862')
Overall, I'd advise you to use from sympy import mpmath as mp and then you can use anything from that package like so: mp.diff(), mp.pi, etc.
Differentiation
sympy.mpmath.diff() (or mp.diff() from now on) computes the derivative of a function at some point x. You need to provide at least the two mandatory arguments; a function of x, and x, the point of interest.
If your function was one like getTotalDeflection(), with only an x input, you could pass it on as is. For example,
def getSlope(self, x):
return mp.diff(self.getTotalDeflection, x)
However, if you want to use a function like beamDeflection(), you'll have to encapsulate it in a function of only x, while you somehow pass on the other argument. For example,
def getSlope(self, x, load):
f_of_x = lambda x: self.beamDeflection(load, x)
return mp.diff(f_of_x, x)
According to the way you've set up the method beamDeflection(), the argument Load is a tuple of two values, i.e. load and position. An example use would be
b.getSlope(1.0, (900, 3.1))
If you want to get the derivative for a list of loads, you'll have to give it a list of lists (or tuples).
def getSlope(self, x, loads):
f_of_x = lambda x: sum(self.beamDeflection(load, x) for load in loads)
return mp.diff(f_of_x, x)
b.getSlope(1.0, [(900, 3.1), (700, 3.8)])
Of course, if the loads you want to use are the ones stored in self.Loads, then you can simply use
def getSlope(self, x):
return mp.diff(self.getTotalDeflection, x)

Related

How to know whether a function is continuous with sympy?

I need to define a function that checks if the input function is continuous at a point with sympy.
I searched the sympy documents with the keyword "continuity" and there is no existing function for that.
I think maybe I should consider doing it with limits, but I'm not sure how.
def check_continuity(f, var, a):
try:
f = sympify(f)
except SympifyError:
return("Invaild input")
else:
x1 = Symbol(var, positive = True)
x2 = Symbol(var, negative = True)
//I don't know what to do after this
I would suggest you use the function continuous_domain. This is defined in the calculus.util module.
Example usage:
>>> from sympy import Symbol, S
>>> from sympy.calculus.util import continuous_domain
>>> x = Symbol("x")
>>> f = sin(x)/x
>>> continuous_domain(f, x, S.Reals)
Union(Interval.open(-oo, 0), Interval.open(0, oo))
This is documented in the SymPy docs here. You can also view the source code here.
Yes, you need to use the limits.
The formal definition of continuity at a point has three conditions that must be met.
A function f(x) is continuous at a point where x = c if
lim x —> c f(x) exists
f(c) exists (That is, c is in the domain of f.)
lim x —> c f(x) = f(c)
SymPy can compute symbolic limits with the limit function.
>>> limit(sin(x)/x, x, 0)
1
See: https://docs.sympy.org/latest/tutorial/calculus.html#limits
Here is a more simple way to check if a function is continues for a specific value:
import sympy as sp
x = sp.Symbol("x")
f = 1/x
value = 0
def checkifcontinus(func,x,symbol):
return (sp.limit(func, symbol, x).is_real)
print(checkifcontinus(f,value,x))
This code output will be - False

Python extracting/editing all constants involved in a function via AST?

Let's say I have the following code:
def f(x, y, n = 1):
k = 10
z = x**n + y**n + k
return z
def g(x):
alpha = 10
return f(x, alpha)
I would like to analyze g to extract from it all constants involved in returning its output: alpha, n, and k. Is it possible to do this in python, perhaps by using the ast library?
Further, if the above is possible, is it then possible to edit some of those constants:
h = create_new_function(g, g.alpha = 25, f.k = 50)
It would be quite something if this were possible!
You can use the ast and
inspect modules to do this task
Use inspect.getsource to get the source of the function where you want to extract the variables.
Parse the function source code to an ast node using ast.compile
Go through the child nodes inside the body of the root node and find instances of the class ast.Assign.
For each assignation, fetch the left & right operands using the attributes targets and value of such nodes
You can do something like this (I assume all values in the assignations are numbers):
import ast
from inspect import getsource
from operator import attrgetter
# This is the function we want to know its variables
def foo():
a, b, c = 1, 2, 3
d = 0
# Get the code and parse it to an ast node
code = getsource(foo)
root = ast.parse(code)
# Get all assignations
assigns = root.body[0].body
for assign in assigns:
# For each assignation...
# Find left operands on the assignation
vars = []
for target in assign.targets:
if isinstance(target, ast.Tuple):
vars.extend(target.elts)
else:
vars.append(target)
# Get operand names
varnames = list(map(attrgetter('id'), vars))
# Also get right operands (we assume are all numbers)
if isinstance(assign.value, ast.Tuple):
values = list(map(attrgetter('n'), assign.value.elts))
else:
values = (assign.value.n,)
# Print info
print(', '.join(varnames) + ' = ' + ', '.join(map(str, values)))
The output of the code above is:
a, b, c = 1, 2, 3
d = 0

How can I manipulate cartesian coordinates in Python?

I have a collection of basic cartesian coordinates and I'd like to manipulate them with Python. For example, I have the following box (with coordinates show as the corners):
0,4---4,4
0,0---4,0
I'd like to be able to find a row that starts with (0,2) and goes to (4,2). Do I need to break up each coordinate into separate X and Y values and then use basic math, or is there a way to process coordinates as an (x,y) pair? For example, I'd like to say:
New_Row_Start_Coordinate = (0,2) + (0,0)
New_Row_End_Coordinate = New_Row_Start_Coordinate + (0,4)
Sounds like you're looking for a Point class. Here's a simple one:
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
def __str__(self):
return "{}, {}".format(self.x, self.y)
def __neg__(self):
return Point(-self.x, -self.y)
def __add__(self, point):
return Point(self.x+point.x, self.y+point.y)
def __sub__(self, point):
return self + -point
You can then do things like this:
>>> p1 = Point(1,1)
>>> p2 = Point(3,4)
>>> print p1 + p2
4, 5
You can add as many other operations as you need. For a list of all of the methods you can implement, see the Python docs.
depending on what you want to do with the coordinates, you can also misuse the complex numbers:
import cmath
New_Row_Start_Coordinate = (0+2j) + (0+0j)
New_Row_End_Coordinate = New_Row_Start_Coordinate + (4+0j)
print New_Row_End_Coordinate.real
print New_Row_End_Coordinate.imag
Python doesn't natively support elementwise operations on lists; you could do it via list comprehensions or map but that's a little clunky for this use case. If you're doing a lot of this kind of thing, I'd suggest looking at NumPy.
For a = (0,2) and b = (0,0) a + b will yield (0, 2, 0, 0), which is probably not what you want. I suggest to use numpy's add function: http://docs.scipy.org/doc/numpy/reference/generated/numpy.add.html
Parameters : x1, x2 : array_like
Returns: The sum of x1 and x2, element-wise. (...)

Sympy: working with equalities manually

I'm currently doing a maths course where my aim is to understand the concepts and process rather than crunch through problem sets as fast as possible. When solving equations, I'd like to be able to poke at them myself rather than have them solved for me.
Let's say we have the very simple equation z + 1 = 4- if I were to solve this myself, I would obviously subtract 1 from both sides, but I can't figure out if sympy provides a simple way to do this. At the moment the best solution I can come up with is:
from sympy import *
z = symbols('z')
eq1 = Eq(z + 1, 4)
Eq(eq1.lhs - 1, eq1.rhs - 1)
# Output:
# z == 3
Where the more obvious expression eq1 - 1 only subtracts from the left-hand side. How can I use sympy to work through equalities step-by-step like this (i.e. without getting the solve() method to just given me the answer)? Any pointers to the manipulations that are actually possible with sympy equalities would be appreciated.
There is a "do" method and discussion at https://github.com/sympy/sympy/issues/5031#issuecomment-36996878 that would allow you to "do" operations to both sides of an Equality. It's not been accepted as an addition to SymPy but it is a simple add-on that you can use. It is pasted here for convenience:
def do(self, e, i=None, doit=False):
"""Return a new Eq using function given or a model
model expression in which a variable represents each
side of the expression.
Examples
========
>>> from sympy import Eq
>>> from sympy.abc import i, x, y, z
>>> eq = Eq(x, y)
When the argument passed is an expression with one
free symbol that symbol is used to indicate a "side"
in the Eq and an Eq will be returned with the sides
from self replaced in that expression. For example, to
add 2 to both sides:
>>> eq.do(i + 2)
Eq(x + 2, y + 2)
To add x to both sides:
>>> eq.do(i + x)
Eq(2*x, x + y)
In the preceding it was actually ambiguous whether x or i
was to be added but the rule is that any symbol that are
already in the expression are not to be interpreted as the
dummy variable. If we try to add z to each side, however, an
error is raised because now it is unclear whether i or z is being
added:
>>> eq.do(i + z)
Traceback (most recent call last):
...
ValueError: not sure what symbol is being used to represent a side
The ambiguity must be resolved by indicating with another parameter
which is the dummy variable representing a side:
>>> eq.do(i + z, i)
Eq(x + z, y + z)
Alternatively, if only one Dummy symbol appears in the expression then
it will be automatically used to represent a side of the Eq.
>>> eq.do(2*Dummy() + z)
Eq(2*x + z, 2*y + z)
Operations like differentiation must be passed as a
lambda:
>>> Eq(x, y).do(lambda i: i.diff(x))
Eq(1, 0)
Because doit=False by default, the result is not evaluated. to
evaluate it, either use the doit method or pass doit=True.
>>> _.doit == Eq(x, y).do(lambda i: i.diff(x), doit=True)
True
"""
if not isinstance(e, (FunctionClass, Lambda, type(lambda:1))):
e = S(e)
imaybe = e.free_symbols - self.free_symbols
if not imaybe:
raise ValueError('expecting a symbol')
if imaybe and i and i not in imaybe:
raise ValueError('indicated i not in given expression')
if len(imaybe) != 1 and not i:
d = [i for i in imaybe if isinstance(i, Dummy)]
if len(d) != 1:
raise ValueError(
'not sure what symbol is being used to represent a side')
i = set(d)
else:
i = imaybe
i = i.pop()
f = lambda side: e.subs(i, side)
else:
f = e
return self.func(*[f(side) for side in self.args], evaluate=doit)
from sympy.core.relational import Equality
Equality.do = do

Memory efficient storage of many large scipy sparse matrices

I need to store around 50.000 scipy sparse csr matrices where each matrix is a vector of length 3.7Million:
x = scipy.sparse.csr_matrix((3.7Mill,1))
I currently store them into a simple dictionary, because I also need to know the corresponding key for each vector (in this case the key is just a simple integer).
The problem now is the huge amount of memory needed. Are there some more efficient ways?
Try to use Lazy data structures.
For example:
def lazy(func):
def lazyfunc(*args, **kwargs):
temp = lambda x : func(*args, **kwargs)
temp.__name__ = "lazy-" + func.__name__
return temp
return lazyfunc
"""
Add some simple functions
"""
def add(x, y):
print "Not lazy"
return x + y
#lazy
def add_lazy(x, y):
print "lazy!"
return x + y
Usage:
>>> add(1, 2)
Not lazy
3
$ add_lazy(1, 2)
<function lazy-add_lazy at 0x021E9470>
>>> myval = add_lazy(1, 2)
>>> myval()
lazy!
3
Look at:
http://finderweb.com/blog/lazy_dict/
http://www.pages.drexel.edu/~kmk592/rants/lazy-python/index.html

Categories

Resources