Why my function cannot draw by matlibplot - python

I set a function like that:
def triangular(x, a, b, c):
if x <= a:
return 0
if a < x <= b:
return (x - a)/(b - a)
if b < x <= c:
return (c - x)/(c - b)
if c < x:
return 0
I want to draw the image of this function so I use:
x = range(-10, 10, 0.1)
y = triangular(x,1,2,3)
plt.figure()
plt.plot(x,y)
plt.show()
However, it shows error:'float' object cannot be interpreted as an integer, why? need I correct my function or input?
I tried to change to
x = np.arange(-10, 10, 0.1)
y = triangular(x,1,2,3)
plt.figure()
plt.plot(x,y)
plt.show()
it shows
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Instead of
x = range(-10, 10, 0.1)
y = triangular(x,1,2,3)
use
import numpy as np
...
x = np.arange(-10, 10, 0.1)
y = [triangular(elem_x,1,2,3) for elem_x in x]

You can also use NumPy indexing and masking to approach this problem avoiding for loops. Below is how you can do it. The conditions I am writing inside the function triangular in the square brackets [...] are just the boundary conditions described in your problem. It is more intuitive in the way it is written
def triangular(x, a, b, c):
x[x<=a] = 0
x[(a<x) & (x<=b)] = (x[(a<x) & (x<=b)] - a)/(b - a)
x[(b<x) & (x<=c)] = (c - x[(b<x) & (x<=c)])/(c - b)
x[x>c] = 0
return x
x = np.arange(-10, 10, 0.1)
y = triangular(x.copy(),1,2,3)
plt.figure()
plt.plot(x,y)
plt.show()

Related

Fastest way to add values to the surface of a sphere in Python?

I have an numpy array that represents my voxelgrid.. Now i want to add values to the surface of a sphere for a given radius. What is the fastest way?
My solution:
def spheric Surface (x, y, z, r, value):
while phi <= (2*math.pi):
eta = math.pi * 2 / 3
while eta <= math.pi:
xx = x + r * math.sin(eta) * math.cos(phi)
yy = y + r * math.sin(eta) * math.sin(phi)
zz = z + r * math.cos(eta)
xx = int(xx*resoultion+0.5)
yy = int(yy*resolution+0.5)
zz = int(zz*resolution+0.5)
voxelGrid[xx][yy][zz] += value
eta += 1/10 * math.pi
phi += 1/10 * math.pi
This is my first Idea: It ist not very fast and not very accurate because with bigger r, i need more angle to calculate.., not just adding 1/10pi for example but 1/5pi, but this makes the code even slower...
Resolution is the resolution of my voxelgrid.. so with Resolution 3, x=2mm would become xx= 6 in the array..
And yes i dont want the whole surface of the sphere, just from 2/3pi to pi...
Is there any better and faster way?
I tried the way with the mask like this, but it is even slower:
def sphericSurface(x, y, z, r, value):
tol = 0.6
grenz = math.pi * 2 / 3
mask = (np.logical_and(np.logical_and((sx[:, None, None] - x) ** 2 + (sy[None, :, None] - y) ** 2 + (sz[None, None, :] - z) ** 2 <= (r + tol)**2,
(sx[:, None, None] - x) ** 2 + (sy[None, :, None] - y) ** 2 + (sz[None, None, :] - z) ** 2 >= (r - tol)**2),
(sz[None, None, :] - z) <= (r*math.cos(grenz))))
x, y, z = np.where(mask==True)
z *= 2
voxelGrid[x,y,z] += value
You can select all of the elements that require modification by generating a mask. I'm not sure how compatible this is which what you already have, but this is the way. It'll basically blow the doors off of the while loop solution speed-wise.
import numpy as np
x = np.arange(0.0,5.0,0.1)
y = np.arange(0.0,5.0,0.1)
z = np.arange(0.0,5.0,0.1)
points = np.array(np.meshgrid(x,y,z)).T
def make_mask(points,a,b,c,r,tol=1e-2):
"""generates a boolean mask of positions within tol distance of the surface of the sphere
(x-a)**2 + (y-b)**2 + (z-c)**2 = r**2"""
mask = (points[...,0]-a)**2+(points[...,1]-b)**2+(points[...,2]-c)**2 < (r+tol)**2
return mask
mask = make_mask(points,2.5,2.5,2.5,1.0,tol=0.2)
# this will tell you all of the points in voxelgrid which need modification
voxelgrid[mask] #will return them all
If you want to add a value to every point near the surface of the sphere you can do
voxelgrid[mask]+=value
provided that the voxelgrid and points coordinates coincide in the sense that voxelgrid[i,j,k] is the container associated with the point points[i,j,k].. you will have to use your resolution parameter to make the x,y,z so that this is true.
Here's a lame plot showing that it works for me:
The code for this plot is
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(*points[mask].T)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
plt.savefig('works.png')
You can maybe calculate the mask more cleanly with something like:
x0 = np.array([a,b,c])
mask = np.sum((points-x0)**2,axis=-1)<(r+tol)**2
but it's a little harder to read. It may be faster ? I am not sure on this. (can anyone weigh in? )

How to implement this activation function in numpy?

How can I implement with numpy:
and its derivative f'(x)? I tried to:
def func (x,y):
if x.all() <= 0:
y = beta (np.exp(x)-1)
return y
elif x>0:
y = x
return y
However they're not working. Note that x and y are arrays.
How about:
def func (x, beta):
y = np.empty_like(x)
mask = x <= 0
y[mask] = beta * (np.exp(x[mask])-1)
y[~mask] = x[~mask]
return y
mask contains the indizes for elements that are <= 0, so that you can seperate the two cases.

Error while using np.sum and functions in python

I am trying to calculate an integral as a summation of points. This is the important part of my code:
I define an array:
x = np.arange(-3,3,0.0223)
For this array I want to define a function shell_charge that sums the values of the bits inside of a shell that I define as r <= x
def piecew(x):
inside_shell = np.where(r <= x)
shell_charge = np.sum(dq[inside_shell])
^^ this is what I am trying to understand and fix
conds = [x == 0, (x >= -0.5) & (x <= 0.5), (x > 0.5) & (x < -0.5)]
funcs = [lambda x: 0.0, lambda x: k * shell_charge * (x)**-2,
lambda x: k * total_charge * (x+0.5)**-2.]
return np.piecewise(x, conds, funcs)
xx = np.linspace(-3, 3, 1000)
plt.plot(xx,piecew(xx))
plt.title("electric field along the x-axis")
plt.xlabel("x position [m]")
plt.ylabel("mag(E) [N/C]")
plt.show()
I am very new to working with arrays and I am not sure how to do this, I would really appreciate any help.

how do I make a numpy.piecewise function of arbitrary length? (having lambda issues)

I'm trying to plot a piecewise fit to my data, but I need to do it with an arbitrary number of line segments. Sometimes there are three segments; sometimes there are two. I'm storing the coefficients of the fit in actable and the bounds on the segments in btable.
Here are example values of my bounds:
btable = [[0.00499999989, 0.0244274978], [0.0244275965, 0.0599999987]]
Here are example values of my coefficients:
actable = [[0.0108687987, -0.673182865, 14.6420775], [0.00410866373, -0.0588355861, 1.07750032]]
Here's what my code looks like:
rfig = plt.figure()
<>various other plot specifications<>
x = np.arange(0.005, 0.06, 0.0001)
y = np.piecewise(x, [(x >= btable[i][0]) & (x <= btable[i][1]) for i in range(len(btable))], [lambda x=x: np.log10(actable[j][0] + actable[j][2] * x + actable[j][2] * x**2) for j in list(range(len(actable)))])
plt.plot(x, y)
The problem is that lambda sets itself to the last instance of the list, so it uses the coefficients for the last segment for all the segments. I don't know how to do a piecewise function without using lambda.
Currently, I'm cheating by doing this:
if len(btable) == 2:
y = np.piecewise(x, [(x >= btable[i][0]) & (x <= btable[i][1]) for i in range(len(btable))], [lambda x: np.log10(actable[0][0] + actable[0][1] * x + actable[0][2] * x**2), lambda x: np.log10(actable[1][0] + actable[1][1] * x + actable[1][2] * x**2)])
else if len(btable) == 3:
y = np.piecewise(x, [(x >= btable[i][0]) & (x <= btable[i][1]) for i in range(len(btable))], [lambda x: np.log10(actable[0][0] + actable[0][1] * x + actable[0][2] * x**2), lambda x: np.log10(actable[1][0] + actable[1][1] * x + actable[1][2] * x**2), lambda x: np.log10(actable[2][0] + actable[2][1] * x + actable[2][2] * x**2)])
else
print('Oh no! You have fewer than 2 or more than 3 segments!')
But this makes me feel icky on the inside. I know there must be a better solution. Can someone help?
This issue is common enough that Python's official documentation has an article Why do lambdas defined in a loop with different values all return the same result? with a suggested solution: create a local variable to be initialized by the loop variable, to capture the changing values of the latter within the function.
That is, in the definition of y it suffices to replace
[lambda x=x: np.log10(actable[j][0] + actable[j][1] * x + actable[j][2] * x**2) for j in range(len(actable))]
by
[lambda x=x, k=j: np.log10(actable[k][0] + actable[k][1] * x + actable[k][2] * x**2) for j in range(len(actable))]
By the way, one can use one-sided inequalities to specify ranges for numpy.piecewise: the last of the conditions that evaluate to True will trigger the corresponding function. (This is a somewhat counterintuitive priority; using the first true condition would be more natural, like SymPy does). If the breakpoints are arranged in increasing order, then one should use "x>=" inequalities:
breaks = np.arange(0, 10) # breakpoints
coeff = np.arange(0, 20, 2) # coefficients to use
x = np.arange(0, 10, 0.1)
y = np.piecewise(x, [x >= b for b in breaks], [lambda x=x, a=c: a*x for c in coeff])
Here each coefficient will be used for the interval that begins with the corresponding breakpoint; e.g., coefficient c=0 is used in the range 0<=x<1, coefficient c=2 in the range 1<=x<2, and so on.

Karatsuba algorithm too much recursion

I am trying to implement the Karatsuba multiplication algorithm in c++ but right now I am just trying to get it to work in python.
Here is my code:
def mult(x, y, b, m):
if max(x, y) < b:
return x * y
bm = pow(b, m)
x0 = x / bm
x1 = x % bm
y0 = y / bm
y1 = y % bm
z2 = mult(x1, y1, b, m)
z0 = mult(x0, y0, b, m)
z1 = mult(x1 + x0, y1 + y0, b, m) - z2 - z0
return mult(z2, bm ** 2, b, m) + mult(z1, bm, b, m) + z0
What I don't get is: how should z2, z1, and z0 be created? Is using the mult function recursively correct? If so, I'm messing up somewhere because the recursion isn't stopping.
Can someone point out where the error is?
NB: the response below addresses directly the OP's question about
excessive recursion, but it does not attempt to provide a correct
Karatsuba algorithm. The other responses are far more informative in
this regard.
Try this version:
def mult(x, y, b, m):
bm = pow(b, m)
if min(x, y) <= bm:
return x * y
# NOTE the following 4 lines
x0 = x % bm
x1 = x / bm
y0 = y % bm
y1 = y / bm
z0 = mult(x0, y0, b, m)
z2 = mult(x1, y1, b, m)
z1 = mult(x1 + x0, y1 + y0, b, m) - z2 - z0
retval = mult(mult(z2, bm, b, m) + z1, bm, b, m) + z0
assert retval == x * y, "%d * %d == %d != %d" % (x, y, x * y, retval)
return retval
The most serious problem with your version is that your calculations of x0 and x1, and of y0 and y1 are flipped. Also, the algorithm's derivation does not hold if x1 and y1 are 0, because in this case, a factorization step becomes invalid. Therefore, you must avoid this possibility by ensuring that both x and y are greater than b**m.
EDIT: fixed a typo in the code; added clarifications
EDIT2:
To be clearer, commenting directly on your original version:
def mult(x, y, b, m):
# The termination condition will never be true when the recursive
# call is either
# mult(z2, bm ** 2, b, m)
# or mult(z1, bm, b, m)
#
# Since every recursive call leads to one of the above, you have an
# infinite recursion condition.
if max(x, y) < b:
return x * y
bm = pow(b, m)
# Even without the recursion problem, the next four lines are wrong
x0 = x / bm # RHS should be x % bm
x1 = x % bm # RHS should be x / bm
y0 = y / bm # RHS should be y % bm
y1 = y % bm # RHS should be y / bm
z2 = mult(x1, y1, b, m)
z0 = mult(x0, y0, b, m)
z1 = mult(x1 + x0, y1 + y0, b, m) - z2 - z0
return mult(z2, bm ** 2, b, m) + mult(z1, bm, b, m) + z0
Usually big numbers are stored as arrays of integers. Each integer represents one digit. This approach allows to multiply any number by the power of base with simple left shift of the array.
Here is my list-based implementation (may contain bugs):
def normalize(l,b):
over = 0
for i,x in enumerate(l):
over,l[i] = divmod(x+over,b)
if over: l.append(over)
return l
def sum_lists(x,y,b):
l = min(len(x),len(y))
res = map(operator.add,x[:l],y[:l])
if len(x) > l: res.extend(x[l:])
else: res.extend(y[l:])
return normalize(res,b)
def sub_lists(x,y,b):
res = map(operator.sub,x[:len(y)],y)
res.extend(x[len(y):])
return normalize(res,b)
def lshift(x,n):
if len(x) > 1 or len(x) == 1 and x[0] != 0:
return [0 for i in range(n)] + x
else: return x
def mult_lists(x,y,b):
if min(len(x),len(y)) == 0: return [0]
m = max(len(x),len(y))
if (m == 1): return normalize([x[0]*y[0]],b)
else: m >>= 1
x0,x1 = x[:m],x[m:]
y0,y1 = y[:m],y[m:]
z0 = mult_lists(x0,y0,b)
z1 = mult_lists(x1,y1,b)
z2 = mult_lists(sum_lists(x0,x1,b),sum_lists(y0,y1,b),b)
t1 = lshift(sub_lists(z2,sum_lists(z1,z0,b),b),m)
t2 = lshift(z1,m*2)
return sum_lists(sum_lists(z0,t1,b),t2,b)
sum_lists and sub_lists returns unnormalized result - single digit can be greater than the base value. normalize function solved this problem.
All functions expect to get list of digits in the reverse order. For example 12 in base 10 should be written as [2,1]. Lets take a square of 9987654321.
» a = [1,2,3,4,5,6,7,8,9]
» res = mult_lists(a,a,10)
» res.reverse()
» res
[9, 7, 5, 4, 6, 1, 0, 5, 7, 7, 8, 9, 9, 7, 1, 0, 4, 1]
The goal of the Karatsuba multiplication is to improve on the divide-and conquer multiplication algorithm by making 3 recursive calls instead of four. Therefore, the only lines in your script that should contain a recursive call to the multiplication are those assigning z0,z1 and z2. Anything else will give you a worse complexity. You can't use pow to compute bm when you haven't defined multiplication yet (and a fortiori exponentiation), either.
For that, the algorithm crucially uses the fact that it is using a positional notation system. If you have a representation x of a number in base b, then x*bm is simply obtained by shifting the digits of that representation m times to the left. That shifting operation is essentially "free" with any positional notation system. That also means that if you want to implement that, you have to reproduce this positional notation, and the "free" shift. Either you chose to compute in base b=2 and use python's bit operators (or the bit operators of a given decimal, hex, ... base if your test platform has them), or you decide to implement for educational purposes something that works for an arbitrary b, and you reproduce this positional arithmetic with something like strings, arrays, or lists.
You have a solution with lists already. I like to work with strings in python, since int(s, base) will give you the integer corresponding to the string s seen as a number representation in base base: it makes tests easy. I have posted an heavily commented string-based implementation as a gist here, including string-to-number and number-to-string primitives for good measure.
You can test it by providing padded strings with the base and their (equal) length as arguments to mult:
In [169]: mult("987654321","987654321",10,9)
Out[169]: '966551847789971041'
If you don't want to figure out the padding or count string lengths, a padding function can do it for you:
In [170]: padding("987654321","2")
Out[170]: ('987654321', '000000002', 9)
And of course it works with b>10:
In [171]: mult('987654321', '000000002', 16, 9)
Out[171]: '130eca8642'
(Check with wolfram alpha)
I believe that the idea behind the technique is that the zi terms are computed using the recursive algorithm, but the results are not unified together that way. Since the net result that you want is
z0 B^2m + z1 B^m + z2
Assuming that you choose a suitable value of B (say, 2) you can compute B^m without doing any multiplications. For example, when using B = 2, you can compute B^m using bit shifts rather than multiplications. This means that the last step can be done without doing any multiplications at all.
One more thing - I noticed that you've picked a fixed value of m for the whole algorithm. Typically, you would implement this algorithm by having m always be a value such that B^m is half the number of digits in x and y when they are written in base B. If you're using powers of two, this would be done by picking m = ceil((log x) / 2).
Hope this helps!
In Python 2.7: Save this file as Karatsuba.py
def karatsuba(x,y):
"""Karatsuba multiplication algorithm.
Return the product of two numbers in an efficient manner
#author Shashank
date: 23-09-2018
Parameters
----------
x : int
First Number
y : int
Second Number
Returns
-------
prod : int
The product of two numbers
Examples
--------
>>> import Karatsuba.karatsuba
>>> a = 1234567899876543211234567899876543211234567899876543211234567890
>>> b = 9876543211234567899876543211234567899876543211234567899876543210
>>> Karatsuba.karatsuba(a,b)
12193263210333790590595945731931108068998628253528425547401310676055479323014784354458161844612101832860844366209419311263526900
"""
if len(str(x)) == 1 or len(str(y)) == 1:
return x*y
else:
n = max(len(str(x)), len(str(y)))
m = n/2
a = x/10**m
b = x%10**m
c = y/10**m
d = y%10**m
ac = karatsuba(a,c) #step 1
bd = karatsuba(b,d) #step 2
ad_plus_bc = karatsuba(a+b, c+d) - ac - bd #step 3
prod = ac*10**(2*m) + bd + ad_plus_bc*10**m #step 4
return prod

Categories