It looks daunting, but please bear with me, it's not as difficult as it looks. I have a code here about beam deflection. It's just some maths and numbers at this point. Only the last part requires attention.
class beam(object):
"""This class is models the deflection of a simply supported beam under
multiple point loads, following Euler-Bernoulli theory and the principle of
superposition.
"""
def __init__(self, E, I, L):
"""The class costructor.
"""
self.E = 8.0E9 # Young's modulus of the beam in N/m^2
self.I = 1.333E-4 # Second moment of area of the beam in m^4
self.L = 5.0 # Length of the beam in m
self.Loads = [(0.0, 0.0)] # the list of loads applied to the beam
self.name = "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 "def __ init __" and "def setLoads" were given, so the above doesn't need changing. I inputted values for self.E, I and L since I thought I needed them there, but those numbers can be replaced back to the letters that they were before.
def beamDeflection(self, Load, x):
"""Just a simple calculation, really.
"""
E = 8.09 * (10 ** 9)
I = 1.333 * (10 ** -4)
L = 5
a = 2.5
b = a + (x - a)
(P1, a) = Load
if 0 <= x <= 2.5:
beamDeflection = ((P1*b*x)/(6*L*E*I))*((L**2)-(x**2)-(b**2))
else:
if 2.5 < x <= 5:
beamDeflection = ((P1*b)/(6*L*E*I)) / (((L/b)*((x-a)**3)) -
(x**3) + (x*((L**2) -
(b**2))))
return beamDeflection
The above "beamDeflection" is the simple code I typed up that just calculates deflection in a beam using a formula that's already been given. Essentially, if a weight is put on the left side of the beam, it'll calculate a number out and the same for the other side.
def getTotalDeflection(self, x):
"""The function getTotalDeflection(self, x) should go through each load tuple in the
list.Loads and calculate the beam deflection at point x (Hint: the function you just
created could be handy here!). getTotalDeflection should return the total deflection at x,
which is the sum over each of the individual deflections.
"""
My understanding is that I need to a "for" loop to go through each load tuple while involving the self.load. I'm not sure on how to go about combining both of those things together. If anyone can help me out, I'd really, really appreciate it.
What you are looking for is probably this (else please clarify):
def getTotalDeflection(self, x):
return sum(self.beamDeflection(loadval, x) for loadval in self.Loads)
I think this is what you want:
def getTotalDeflection(self, x):
total = 0
# For every load in `Loads`
for load in self.Loads:
# Compute the deflection and add it to the total
total += self.beamDeflection(load, x):
return total
Related
I have just almost finished my assignment and now the only thing I have left is to define the tostring method shown here.
import math
class RegularPolygon:
def __init__(self, n = 1, l = 1):
self.__n = n
self.__l = l
def set_n(self, n):
self.__n = n
def get_n(self):
return self.__n
def addSides(self, x):
self.__n = self.__n + x
def setLength(self, l ):
self.__l = l
def getLength(self):
return self.__l
def setPerimeter(self):
return (self.__n * self.__l )
def getArea(self):
return (self.__l ** 2 / 4 * math.tan(math.radians(180/self.__n)))
def toString(self):
return
x = 3
demo_object = RegularPolygon (3, 1)
print(demo_object.get_n() , demo_object.getLength())
demo_object.addSides(x)
print(demo_object.get_n(), demo_object.getLength())
print(demo_object.getArea())
print(demo_object.setPerimeter())
Basically the tostring on what it does is return a string that has the values of the internal variables included in it. I also need help on the getArea portion too.
Assignment instructions
The assignment says
... printing a string representation of a RegularPolygon object.
So I would expect you get to choose a suitable "representation". You could go for something like this:
return f'{self.__n+2} sided regular polygon of side length {self.__l}'
or as suggested by #Roy Cohen
return f'{self.__class__.__name__}({self.__n}, {self.__l})'
However, as #Klaus D. wrote in the comments, Python is not Java, and as such has its own standards and magic methods to use instead.
I would recommend reading this answer for an explanation between the differences between the two built-in string representation magic-methods: __repr__ and __str__. By implementing these methods, they will automatically be called whenever using print() or something similar, instead of you calling .toString() every time.
Now to address the getters and setters. Typically in Python you avoid these and prefer using properties instead. See this answer for more information, but to summarise you either directly use an objects properties, or use the #property decorator to turn a method into a property.
Edit
Your area formula is likely an error with order-of-operations. Make sure you are explicit with which operation you're performing first:
return self.__l ** 2 / (4 * math.tan(math.radians(180/self.__n)) )
This may be correct :)
I'm implementing a Markov Chain Montecarlo with metropolis and barkes alphas for numerical integration. I've created a class called MCMCIntegrator(). I've loaded it with some attributes, one of then is the pdf of the function (a lambda) we're trying to integrate called g.
import numpy as np
import scipy.stats as st
class MCMCIntegrator:
def __init__(self):
self.g = lambda x: st.gamma.pdf(x, 0, 1, scale=1 / 1.23452676)*np.abs(np.cos(1.123454156))
self.size = 10000
self.std = 0.6
self.real_int = 0.06496359
There are other methods in this class, the size is the size of the sample that the class must generate, std is the standard deviation of the Normal Kernel, which you will see in a few seconds. The real_int is the value of the integral from 1 to 2 of the function we're integrating. I've generated it with a R script. Now, to the problem.
def _chain(self, method=None):
"""
Markov chain heat-up with burn-in
:param method: Metrpolis or barker alpha
:return: np.array containing the sample
"""
old = 0
sample = np.zeros(int(self.size * 1.5))
i = 0
if method:
def alpha(a, b): return min(1, self.g(b) / self.g(a))
else:
def alpha(a, b): return self.g(b) / (self.g(a) + self.g(b))
while i != len(sample):
new = st.norm(loc=old, scale=self.std).rvs()
new = abs(new)
al = alpha(old, new)
u = st.uniform.rvs()
if al > u:
sample[i] = new
old = new
i += 1
return np.array(sample)
Below this method is an integrate() method that calculates the proportion of numbers in the [1, 2] interval:
def integrate(self, method=None):
"""
Integration step
"""
sample = self._chain(method=method)
# discarding 30% of the sample for the burn-in
ind = int(len(sample)*0.3)
sample = sample[ind:]
setattr(self, "sample", sample)
sample = [1 if 1 < v < 2 else 0 for v in sample]
return np.mean(sample)
This is the main function:
def main():
print("-- RESULTS --".center(20), end='\n')
mcmc = MCMCIntegrator()
print(f"\t{mcmc.integrate()}", end='\n')
print(f"\t{np.abs(mcmc.integrate() - mcmc.real_int) / mcmc.real_int}")
if __name__ == "__main__":
main()
I'm stuck in an infinity while loop and I have no idea why this is happening.
Couple things... You are hung up in the chain method because the alpha computation is returning NaN, because g() is returning NaN. Take a look at the print statements I inserted into your code and run it...
tips:
Make g() a class function just like chain.
Test g() on some test values, something is clearly amiss
Don't conditionally define a function like alpha. Wayyy confusing and error prone/tough to troubleshoot. Just pass alpha what it needs and you also can make it a class function alpha(a, b, method=None)
Take a look at where you are updating i in the `_chain' function.... You realize you are risking a long looping process because you only update i conditionally!
You are set up for disaster with your use of numpy array. You may have a bunch of trailing zeros after your actual data because you are over-writing the large zeros list. You do NOT need numpy array here, just use a python empty list and append new values to it, either zero or one...based on whatever.
Add a couple print statements in when you are troubleshooting (or unit test your functions). Try my adds to your function below... it is what I used to figure out what was going on
def _chain(self, method=None, verbose=True):
"""
Markov chain heat-up with burn-in
:param method: Metrpolis or barker alpha
:return: np.array containing the sample
"""
old = 0
sample = np.zeros(int(self.size * 1.5))
i = 0
if method:
def alpha(a, b): return min(1, self.g(b) / self.g(a))
else:
def alpha(a, b):
if verbose: print(f'g(a): {self.g(a)}, g(b): {self.g(b)}')
return self.g(b) / (self.g(a) + self.g(b))
while i != len(sample):
new = st.norm(loc=old, scale=self.std).rvs()
new = abs(new)
al = alpha(old, new)
u = st.uniform.rvs()
if verbose: print(f'old: {old:.3f} new: {new:.3f} alpha: {al:.3f} u: {u:.3f}')
if al > u:
sample[i] = new
old = new
i += 1 # do you really want to conditionally update i?
sys.exit(-1) # to breakout of infinite loop...
return np.array(sample)
so I have to process a 2 by 2 matrix through a class and return print the output with str. I can't really create new functions and I'm pretty sure the math is good with the matrices, I'm just having some output issues. I marked the area, specifically really the output that I cannot modify, but I can modify the class to support it.
Here's my code.
# This code aims to take a 2 by 2 matrix and add, subtract, and multiply it by another matrix, as well as inverse and power it.
# ----------------------------------------------------------------------------------------------------------------------
# This is how we'll use math.nan and only math.nan
import math
# Your classes should go here
class Matrix2x2: # Just initializing as needed.
def __init__(self,a,b,c,d):
self.a = a
self.b = b
self.c = c
self.d = d
def __add__(self,second):
return(Matrix2x2(self.a+second.a,self.b+second.b,self.c+second.c,self.d+second.d))
def __sub__(self, second): # Just subtracting instead of adding
return(Matrix2x2(self.a - second.a,self.b-second.b,self.c-second.c,self.d-second.d))
def __mul__(self, second): # Multiplying them based on the according spot and some addition.
return(Matrix2x2(self.a*second.a+self.b*second.c,self.a*second.b+self.b*second.d,self.c*second.a+self.d*second.c,self.c*second.b+self.d*second.d))
def __pow__(self, power): # Process varies based on what we work with.
StoredMatrix = Matrix2x2(self.a, self.b, self.c, self.d) # The variables just save information and make the math more clean.
determinant = 1/((self.a*self.d)-(self.b*self.c)) # Used to simplify inversing and determine if there is an inverse.
InverseMatrix = Matrix2x2(self.d*determinant,-self.b*determinant,-self.c*determinant, self.a*determinant)
if power > 0:
count = 1
while count < power: # The original matrix is repeatedly multiplied and stored until it matches the power value.
count+=1
StoredMatrix *= Matrix2x2(self.a, self.b, self.c, self.d)
return StoredMatrix
elif power < 0:
count = 0
while count < power:
count+=1
InverseMatrix *= Matrix2x2(self.d*determinant,-self.b*determinant,-self.c*determinant,self.a*determinant)
return InverseMatrix
if determinant == 0 or power == 0: # This means that there is no inverse, or the power value is 0 and invalid.
return(Matrix2x2(math.nan, math.nan, math.nan, math.nan))
def __str__(self):
return print('[',str(self.a) ,str(self.b) ,']\n' ,'\b[' ,str(self.c) ,str(self.d),']')
# Do NOT use any pre-built packages to perform the below operations, each should
# be coded using regular mathematics operation (+,-,*,/), no numpy or math functions other
# than math.nan
# Code below cannot be modified
A = Matrix2x2(1,2,3,4)
B = Matrix2x2(4,3,2,1)
print('Addition: A+B')
print(A,"+\n",B,"=\n",A+B,sep="")
input(),print('Subtraction: A-B')
print(A,"-\n",B,"=\n",A-B,sep="")
input(),print('Multiplication: A*B')
print(A,"*\n",B,"=\n",A*B,sep="")
input(),print('Multiplication: B*A')
print(B,"*\n",A,"=\n",B*A,sep="")
input(),print('Powers: A^3 ')
print(A,"^3","\n=\n",A**3,sep="")
input(),print('Inverse: A^-1 ')
print(A,"^-1","\n=\n",A**(-1),sep="")
input(),print('Inverse with powers: A^-3 = (A^-1)^3')
print(A,"^-3","\n=\n",A**(-3),sep="")
# code above cannot be modified
# Just for testing, below.
print(A.__add__(B))
print(A.__sub__(B))
print(A.__mul__(B))
print(A.__pow__(3))
print(A.__pow__(-1))
print(A.__pow__(0))
print(A.__pow(-3))
I usually get an error due a NoneType with the add function. This doesn't allow me to see what errors I'd get. I tried just converting them to strings individually using str() and got the same error. I don't think it's the math.nan's either.
Here is an example:
Addition: A+B
[ 1 2 ]
[ 3 4 ]
Traceback (most recent call last):
File "ThisWasPurposelyCensored", line 51, in <module>
print(A,"+\n",B,"=\n",A+B,sep="")
TypeError: __str__ returned non-string (type NoneType)
Process finished with exit code 1
Anyways, how do I avoid that NoneType issue or get this to be compatible with str, without interfering with the math and required input too much? I'll provide anymore information you might need to help me solve this.
Rewrite your __str__ method to be like this
def __str__(self):
return '[ {} {} ]\n[ {} {} ]'.format(self.a, self.b, self.c, self.d)
A bit shorter
def __str__(self):
return '[ {x.a} {x.b} ]\n[ {x.c} {x.d} ]'.format(x=self)
import math
class Vector():
vA = [3.183, 7.627]
def magnitude(vector):
sum = 0
i = 0
while i < len(vector):
sum += vector[i]
i += 1
return math.sqrt(sum)
def unitVector(vector):
print( 1 / (magnitude(vA) * vA))
I'm attempting to code some linear algebra and calculate the unit vectors for the vector 'vA' stated above. When I run the code I get NameError: global name 'magnitude' is not defined. I do not understand why I am having an issue with simply calling one function from another.
I'm a beginner with python and I'm assuming I have a misunderstanding about classes and functions, but I have looked through the documentation and cannot find the answer I am looking for.
You have several errors in your code:
def magnitude(vector) should be def magnitude(self, vector)
def unitVector(vector) should be def unitVector(self, vector)
magnitude(vA) should be self.magnitude(vA)
EDIT:
A better way of writing your class would be to use OOP concepts in Python, so you do not have to pass vector as a function argument if you make it an instance variable.
Your class can be rewrote like this:
import math
class Vector():
def __init__(self, vector):
self.vector = vector
def magnitude(self):
sum = 0
i = 0
while i < len(self.vector):
sum += self.vector[i]
i += 1
return math.sqrt(sum)
def unitVector(self):
print( 1 / (self.magnitude() * self.vector))
vA = [3.183, 7.627]
vec = Vector(vA)
vec.unitVector()
Be aware that it does not work. Because in unitVector, Python doesn't know how to multiply a float by a list (self.magnitude() returns a float and self.vector is a list). You probably want to rework this part.
i would like to perform a calculation using python, where the current value (i) of the equation is based on the previous value of the equation (i-1), which is really easy to do in a spreadsheet but i would rather learn to code it
i have noticed that there is loads of information on finding the previous value from a list, but i don't have a list i need to create it! my equation is shown below.
h=(2*b)-h[i-1]
can anyone give me tell me a method to do this ?
i tried this sort of thing, but that will not work as when i try to do the equation i'm calling a value i haven't created yet, if i set h=0 then i get an error that i am out of index range
i = 1
for i in range(1, len(b)):
h=[]
h=(2*b)-h[i-1]
x+=1
h = [b[0]]
for val in b[1:]:
h.append(2 * val - h[-1]) # As you add to h, you keep up with its tail
for large b list (brr, one-letter identifier), to avoid creating large slice
from itertools import islice # For big list it will keep code less wasteful
for val in islice(b, 1, None):
....
As pointed out by #pad, you simply need to handle the base case of receiving the first sample.
However, your equation makes no use of i other than to retrieve the previous result. It's looking more like a running filter than something which needs to maintain a list of past values (with an array which might never stop growing).
If that is the case, and you only ever want the most recent value,then you might want to go with a generator instead.
def gen():
def eqn(b):
eqn.h = 2*b - eqn.h
return eqn.h
eqn.h = 0
return eqn
And then use thus
>>> f = gen()
>>> f(2)
4
>>> f(3)
2
>>> f(2)
0
>>>
The same effect could be acheived with a true generator using yield and send.
First of, do you need all the intermediate values? That is, do you want a list h from 0 to i? Or do you just want h[i]?
If you just need the i-th value you could us recursion:
def get_h(i):
if i>0:
return (2*b) - get_h(i-1)
else:
return h_0
But be aware that this will not work for large i, as it will exceed the maximum recursion depth. (Thanks for pointing this out kdopen) In that case a simple for-loop or a generator is better.
Even better is to use a (mathematically) closed form of the equation (for your example that is possible, it might not be in other cases):
def get_h(i):
if i%2 == 0:
return h_0
else:
return (2*b)-h_0
In both cases h_0 is the initial value that you start out with.
h = []
for i in range(len(b)):
if i>0:
h.append(2*b - h[i-1])
else:
# handle i=0 case here
You are successively applying a function (equation) to the result of a previous application of that function - the process needs a seed to start it. Your result looks like this [seed, f(seed), f(f(seed)), f(f(f(seed)), ...]. This concept is function composition. You can create a generalized function that will do this for any sequence of functions, in Python functions are first class objects and can be passed around just like any other object. If you need to preserve the intermediate results use a generator.
def composition(functions, x):
""" yields f(x), f(f(x)), f(f(f(x)) ....
for each f in functions
functions is an iterable of callables taking one argument
"""
for f in functions:
x = f(x)
yield x
Your specs require a seed and a constant,
seed = 0
b = 10
The equation/function,
def f(x, b = b):
return 2*b - x
f is applied b times.
functions = [f]*b
Usage
print list(composition(functions, seed))
If the intermediate results are not needed composition can be redefined as
def composition(functions, x):
""" Returns f(x), g(f(x)), h(g(f(x)) ....
for each function in functions
functions is an iterable of callables taking one argument
"""
for f in functions:
x = f(x)
return x
print composition(functions, seed)
Or more generally, with no limitations on call signature:
def compose(funcs):
'''Return a callable composed of successive application of functions
funcs is an iterable producing callables
for [f, g, h] returns f(g(h(*args, **kwargs)))
'''
def outer(f, g):
def inner(*args, **kwargs):
return f(g(*args, **kwargs))
return inner
return reduce(outer, funcs)
def plus2(x):
return x + 2
def times2(x):
return x * 2
def mod16(x):
return x % 16
funcs = (mod16, plus2, times2)
eq = compose(funcs) # mod16(plus2(times2(x)))
print eq(15)
While the process definition appears to be recursive, I resisted the temptation so I could stay out of maximum recursion depth hades.
I got curious, searched SO for function composition and, of course, there are numerous relavent Q&A's.