Get results from sympy units - physics

I'm trying to get some electrodynamics going with units in sympy. To check how i'm doing, i'm checking this relation:
So i have defined mu0 and epsilon 0, and i would like to get the speed of light out:
import sympy.physics.units as u
import sympy as sp
sp.sqrt(1/(u.magnetic_constant*u.electric_constant))
>>>> 1/(sqrt(magnetic_constant)*sqrt(vacuum_permittivity))
So my result is not so useful. I have tried to find solutions online, bit i can't figure it out. Would love your input

You can simply use the convert_to function defined in the units module:
In [3]: expr = sp.sqrt(1/(u.magnetic_constant*u.electric_constant))
In [4]: expr
Out[4]:
1
─────────────────────────────────────────────
___________________ _____________________
╲╱ magnetic_constant ⋅╲╱ vacuum_permittivity
In [5]: u.convert_to(expr, u.speed_of_light)
Out[5]: speed_of_light
In [6]: u.convert_to(expr, u.meter/u.second)
Out[6]:
299792458⋅meter
───────────────
second

Related

Unexpected output when passing array as argument of a vectorized function

In the example code below
import numpy as np
def f(x):
print(x)
x = np.array([[ 0.31432202, 7.94263361],
[-0.5346868, 1.93901039],
[-0.47571535, 4.17720033]])
np.vectorize(f)(x[0,:])
As output, I expected to get something like
[ 0.31432202 7.94263361]
Instead I get
0.31432202
0.31432202
7.94263361
Can anyone tell me what is wrong with it? Thank you
How much of the np.vectorize docs did you read?
In [129]: def f(x):
...: print(x)
...:
...: x = np.array([[ 0.31432202, 7.94263361],
...: [-0.5346868, 1.93901039],
...: [-0.47571535, 4.17720033]])
In [130]: f1=np.vectorize(f)
In [131]: f1(1)
1
1
Out[131]: array(None, dtype=object)
f gets called twice, once to determine the return dtype, and once for each element. Try it with 3 elements:
In [132]: f1([1,2,3])
1
1
2
3
Out[132]: array([None, None, None], dtype=object)
Note that the return is an array with None. That's because your f doesn't have a return statement. It just does the print.
Why are you using np.vectorize? It has a clear performance disclaimer. It also talks about the return dtype and how it determines that. It's not a high performance way of calling a function that just prints something. It may be useful for running a function of several scalar values, and you want to take advantage of numpy broadcasting.
Read the docs.

In numpy, is there a function to find the inverse of ix_?

With numpy, my goal is to select a quadratic submatrix from a quadratic matrix, and then also look at the collection of elements that are not in the first submatrix.
For the first submatrix, I'm using np.ix_:
import numpy as np
r = np.random.rand(3,3)
l = [1,2]
r[np.ix_(l, l)]
Then, r[np.ix_(l, l)] will pick out a 2x2 matrix, marked by **:
0
1
2
0
r0,0
r0,1
r0,2
1
r1,0
** r1,1 **
** r1,2**
2
r2,0
** r2,1 **
** r2,2 **
But now what is the best approach to select the difference between the submatrix and the parent matrix?
I have looked at:
~np.ix_, like ~np.eye, but this doesn't seem to be supported
np.subtract, but the problem is that I need to select the elements by their indices and not by their values.
Based on a comment by #hpaulj, I followed the approach with the numpy.ma submodule:
import numpy as np
r = np.random.rand(3,3)
l = [1,2]
r[np.ix_(l, l)]
import numpy.ma as ma
mask = ma.zeros(r.shape)
mask[np.ix_(l, l)] = 1
Then, ma.compressed() gives the desired result:
ma.compressed(ma.array(r, mask=mask))
Using np.ix_ is equivalent to using basic indexing, but by triggering advanced indexing.
So it lets you fetch all the elements belonging to the 1st and 2nd rows and 1st and 2nd columns completely as a copy (basic indexing yields a view)
import numpy as np
r = np.random.rand(3,3)
l = [1,2]
r[np.ix_(l, l)]
array([[0.46899841, 0.49051596],
[0.00256912, 0.86447371]])
Equivalent to np.ix_, using basic indexing (this is a view and not a copy!) -
r[1:3, 1:3]
array([[0.46899841, 0.49051596],
[0.00256912, 0.86447371]])
If you, however, want to fetch the (1,1) and (2,2) index elements, then you can directly use advance indexing as below -
r[l,l]
array([0.46899841, 0.86447371])
As you can see, this returns the diagonal elements which you are looking for (with the np.eye for example)
Read more about how indexing (basic and advance) works here or check out a detailed answer where I explain this as well here.

Explination of numpy's einsum

I am currently doing some studies on computing a 4th order tensor in numpy with the einsum function.
The tensor I am computing is written in Einstein notation and the function einsun does the work perfectly! But I would like to know what it is doing in the following case:
import numpy as np
a=np.array([[2,0,3],[0,1,0],[0, 0, 4]])
b= np.eye(3)
r1=np.einsum("ij,kl->ijkl", a, b)
r2=np.einsum("ik,jl->ijkl", a, b)
in r1 I am basically doing the standard tensor product (equivalent to np.tensordot(a,b,axes=0)).
What about in r2?
I know I can get the value by doing a[:,None,:,None]*b[None,:,None,:] but I do not know what the indexing is doing. Does this operation have a name?
Sorry if this is too basic!
I tried to use the transpose definition to change multiple axes.
It works for 'ij,kl -> ijkl' , 'ik,jl->ijkl' ,'kl,ij->ijkl'
but fails for 'il,jk->ijkl', 'jl,ik->ijkl'and 'jk,il->ijkl'
import numpy as np
a=np.eye(3)
a[0][0]=2
a[0][-1]=3
a[-1][-1]=4
b=np.eye(3)
def permutation(str_,Arr):
Arr=np.reshape(Arr,[3,3,3,3])
def splitString(str_):
tmp1=str_.split(',')
tmp2=tmp1[1].split('->')
str_idx1=tmp1[0]
str_idx2=tmp2[0]
str_idx_out=tmp2[1]
return str_idx1,str_idx2, str_idx_out
idx_a, idx_b, idx_out=splitString(str_)
dict_={'i':0,'j':1,'k':2,'l':3}
def split(word):
return [char for char in word]
a,b=split(idx_a)
c,d=split(idx_b)
Arr=np.transpose(Arr,(dict_[a],dict_[b],dict_[c],dict_[d]))
return Arr
str_='jk,il->ijkl'
d=np.outer(a,b)
f=np.einsum(str_, a,b)
check=permutation(str_,d)
if (np.count_nonzero(f-check)==0):
print ('Code is working!')
else:
print("Something is wrong...")
Appreciate your suggestions!
r2 is essentially the same tensor as r1, but the indices are rearranged. In particular, r2[i,j,k,l] is equal to a[i,k]*b[k,l].
For instance:
>>> r2[0,1,2,1]
3.0
This corresponds to the fact that a[0,2]*b[1,1] is 3 * 1, which is indeed 3.
Another way to think about this is to observe that a[:,j,:,l] is equal to a whenever j == l and is a zero-matrix otherwise.

IPython Notebook cell multiple outputs

I am running this cell in IPython Notebook:
# salaries and teams are Pandas dataframe
salaries.head()
teams.head()
The result is that I am only getting the output of teams data-frame rather than of both salaries and teams. If I just run salaries.head() I get the result for salaries data-frame but on running both the statement I just see the output of teams.head(). How can I correct this?
have you tried the display command?
from IPython.display import display
display(salaries.head())
display(teams.head())
An easier way:
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
It saves you having to repeatedly type "Display"
Say the cell contains this:
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
a = 1
b = 2
a
b
Then the output will be:
Out[1]: 1
Out[1]: 2
If we use IPython.display.display:
from IPython.display import display
a = 1
b = 2
display(a)
display(b)
The output is:
1
2
So the same thing, but without the Out[n] part.
IPython Notebook shows only the last return value in a cell. The easiest solution for your case is to use two cells.
If you really need only one cell you could do a hack like this:
class A:
def _repr_html_(self):
return salaries.head()._repr_html_() + '</br>' + teams.head()._repr_html_()
A()
If you need this often, make it a function:
def show_two_heads(df1, df2, n=5):
class A:
def _repr_html_(self):
return df1.head(n)._repr_html_() + '</br>' + df2.head(n)._repr_html_()
return A()
Usage:
show_two_heads(salaries, teams)
A version for more than two heads:
def show_many_heads(*dfs, n=5):
class A:
def _repr_html_(self):
return '</br>'.join(df.head(n)._repr_html_() for df in dfs)
return A()
Usage:
show_many_heads(salaries, teams, df1, df2)
Enumerating all the solutions:
sys.displayhook(value), which IPython/jupyter hooks into. Note this behaves slightly differently from calling display, as it includes the Out[n] text. This works fine in regular python too!
display(value), as in this answer
get_ipython().ast_node_interactivity = 'all'. This is similar to but better than the approach taken by this answer.
Comparing these in an interactive session:
In [1]: import sys
In [2]: display(1) # appears without Out
...: sys.displayhook(2) # appears with Out
...: 3 # missing
...: 4 # appears with Out
1
Out[2]: 2
Out[2]: 4
In [3]: get_ipython().ast_node_interactivity = 'all'
In [2]: display(1) # appears without Out
...: sys.displayhook(2) # appears with Out
...: 3 # appears with Out (different to above)
...: 4 # appears with Out
1
Out[4]: 2
Out[4]: 3
Out[4]: 4
Note that the behavior in Jupyter is exactly the same as it is in ipython.
Provide,
print salaries.head()
teams.head()
This works if you use the print function since giving direct commands only returns the output of last command.
For instance,
salaries.head()
teams.head()
outputs only for teams.head()
while,
print(salaries.head())
print(teams.head())
outputs for both the commands.
So, basically, use the print() function

The random number generator in numpy

I am using the numpy.random.randnand numpy.random.randto generate random numbers. I am confusing about the difference between random.randn and random.rand?
The main difference between the two is mentioned in the docs. Links to Doc rand and Doc randn
For numpy.rand, you get random values generated from a uniform distribution within 0 - 1
But for numpy.randn you get random values generated from a normal distribution, with mean 0 and variance 1.
Just a small example.
>>> import numpy as np
>>> np.random.rand(10)
array([ 0.63067838, 0.61371053, 0.62025104, 0.42751699, 0.22862483,
0.75287427, 0.90339087, 0.06643259, 0.17352284, 0.58213108])
>>> np.random.randn(10)
array([ 0.19972981, -0.35193746, -0.62164336, 2.22596365, 0.88984545,
-0.28463902, 1.00123501, 1.76429108, -2.5511792 , 0.09671888])
>>>
As you can see that rand gives me values within 0-1,
whereas randn gives me values with mean == 0 and variance == 1
To explain further, let me generate a large enough sample:
>>> a = np.random.rand(100)
>>> b = np.random.randn(100)
>>> np.mean(a)
0.50570149531258946
>>> np.mean(b)
-0.010864958465191673
>>>
you can see that the mean of a is close to 0.50, which was generated using rand. The mean of b on the other hand is close to 0.0, which was generated using randn
You can also get a conversion from rand numbers to randn numbers in Python by the application of percent point function (ppf) for the Normal Distribution with random variables distributed ~ N(0,1). It is a well-known method of projecting any uniform random variables (0,1) onto ppf in order to get random variables for a desired cumulative distribution.
In Python we can visualize that process as follows:
from numpy.random import rand
import matplotlib.pyplot as plt
from scipy.stats import norm
u = rand(100000) # uniformly distributed rvs
z = norm.ppf(u) # ~ N(0,1) rvs
plt.hist(z,bins=100)
plt.show()