Generate Random Numbers Within A Seed - python

Relatively new to python so apologies for any terrible coding.
I'm using blender to create random stimuli sets using the sapling add on to create something like
I also want to define a random camera position and angle in a hemisphere above the plane which I do by producing two random numbers (u and v in my example below).
However, calling the py.ops.curve.tree_add function (which generates the tree) sets some kind of seed which means that the random numbers I produce are always the same.
E.g. in the example code it creates a range of different trees depending on the randint() generated for basesize/ basesplit.
However, for each unique tree these generate, the random numbers u and v are always the same. This means for every random tree I generate, the camera angle is specific for that tree (and not completely random)
I assume this occurs via some seed, so I was wondering if there is a way to tell python to generate a random number and ignore any seeds?
Best,
Example code: (import bpy is the python api module for blender)
### libraries
import bpy
from random import random, randint
u = random()
v = random()
obj = bpy.ops.curve.tree_add(bevel = True,
prune = True,
showLeaves = True,
baseSize = randint(1,10)/10,
baseSplits = randint(0,4))
print(u)
print(v)
in case it helps, my function to generate a sphere to place the camera and then point it towards the object is (I haven't included the libraries/ rest of the script etc. here for brevity- it creates a point around a defined centre which is a radius r away and works apart from the above issue):
#generate the position of the new camera
def randomSpherePoint(sphere_centre, r, u, v):
theta = 2 * pi * u
phi = acos(2 * v - 1)
x = centre[0] + (r * sin(phi) * cos(theta))
y = centre[1] + (r * sin(phi) * sin(theta))
z = fabs(centre[2] + (r * cos(phi)))
return(x,y,z)
hemisphere_point = randomSpherePoint(centre, radius, u, v)
print(hemisphere_point)
#add a camera at this randomly generated hemispheric location
bpy.ops.object.camera_add(location = hemisphere_point)
the_camera = bpy.data.objects["Camera"]
#rotate the camera to the centre of the plane
camera_direction = centre - camera_location
camera_rotation = camera_direction.to_track_quat('-Z', 'Y')
the_camera.rotation_euler = camera_rotation.to_euler()

You can make a instance of random using the class random.Random.
An example would be:
randomgen = random.Random()
randomgen.uniform(0,1)
This reason is:
The functions supplied by this module are actually bound methods of a hidden instance of the random.Random class. You can instantiate your own instances of Random to get generators that don’t share state
(from https://docs.python.org/3/library/random.html)

Python's random module provides the seed() method for you to set the seed.
import random
random.seed(12)
random.randint(0,100)
Another option to get variations in your trees is to provide a different seed for the sapling addon to work with. You can find it in the operator adjustment panel above the tree scale, the python API also accepts a seed paramater.
bpy.ops.curve.tree_add(seed=myseed)

Related

Distance measuring with turtle Python

I have written a programme that creates a random walk using certain distribution. For example, if it is a Cauchy distribution, the program generates an adequate random number and appends it to the list. Then this list is used by the turtle as a list of steps in a random direction. Now I would like to measure the distance between the turtle in each step and point (0,0) where the random walk is starting and I can't seem to find a good solution for that. It cannot be done with turtle.distance() because I want to draw a graph of dependence this distance on step count. My first idea was to get coordinates of each point that my turtle stops and then try to calculate distance using the Pythagoras theorem, but I make mistakes somewhere along the road and can't acquire them. Could someone explain why, please? Or maybe there is a better way to do this?
cauchylist = []
for i in randomlist:
cauchylist.append(0.15*math.tan(((i-0.5)*math.pi)) )
Franklin = turtle.Turtle()
u = input("Which walk to walk? C - Cauchy or G - Gauss.")
if u == "C":
start()
walk(Franklin, cauchylist)
cv = turtle.getcanvas()
cv.postscript(file="walk_cauchy.ps")
Franklin.penup()
Franklin.fd()
Franklin.end_poly()
coordinates = Franklin.get_poly()
turtle.done()
The distance of the current position of the turtle to the origin is calculated by squaring the posi-values, adding them and getting the square root from that:
from turtle import *
from math import sqrt
from random import seed, choice
seed(42) # ensure same randoms for demonstation purposes
def calc_dist(t):
return sqrt(sum(map(lambda x:x*x, t.pos())))
t = Turtle()
dists = []
for _ in range(20):
t.forward(choice(range(100))-50)
t.left(choice(range(360))-180)
dists.append(calc_dist(t))
print(dists)
Output:
[31.0, 68.97157492789178, 87.25113481192517, 98.48389701852805, 134.17622966161073,
141.40760908816227, 138.90181656585844, 128.76423765225354, 113.79561063931857,
108.70118700467432, 66.53516784607132, 87.40888728250773, 113.65616399911761,
115.22672747425487, 122.12225694530929, 128.35176588895283, 157.57222689310848,
128.33399580245668, 129.3846600939952, 153.87822281203412]
Do the calculation sqrt(sum(map(lambda x:x*x, t.pos()))) after each move of the turtle and store the result in a list.
get_poly() will return a tuple of tuples.
Example:
coordinates = turtle.get_poly()
coordinates = ((0.00,0.00), (100.00,0.00), (128.19,10.26), (136.87,59.50))
You can easily acess each tuple with a for loop
for c in coordinates:
print(c)
Output:
(0.00,0.00)
(100.00,0.00)
(128.19,10.26)
(136.87,59.50)
I would like to measure the distance between the turtle in each step
and point (0,0) where the random walk is starting and I can't seem to
find a good solution for that. It cannot be done with
turtle.distance()
This premise doesn't hold. We can do turtle.distance(0, 0) which doesn't affect the turtle's state but gives us the distance to the origin. To demonstrate, my rework of #PatrickArtner's example using distance():
from turtle import Screen, Turtle
from random import seed, randint
seed(42) # repeatable randomness for demonstration purposes
screen = Screen()
turtle = Turtle()
distances = []
for _ in range(20):
turtle.forward(randint(-50, 50))
turtle.left(randint(-180, 180))
distances.append(turtle.distance(0, 0))
print(distances)
screen.exitonclick()
Console Output
> python3 test.py
[31.0, 68.97157492789178, 87.25113481192517, 98.48389701852807, 134.17622966161073,
141.40760908816227, 138.90181656585844, 128.7642376522535, 113.79561063931855,
108.70118700467431, 66.5351678460713, 87.4088872825077, 113.65616399911758,
115.22672747425486, 122.12225694530927, 128.35176588895283, 157.57222689310848,
128.33399580245668, 129.3846600939952, 153.87822281203412]
>
I cannot use t.forward and t.left commands because I get an error
"invalid command name . canvas turtle". I think it's because my turtle
walk is defined by function looking like that:
def walk(turtle, steps):
x = 0
y = 0
for i in steps:
kat = random.random() * 360
turtle.setheading(kat)
turtle.forward(math.fabs(i))
bounds(turtle)
However, if I don't use it as on the example You gave, I create list
full of only last distance value. Can anything be done about that?
We'd need to see more code to address this issue, e.g. the definition of bounds() and so forth.

Solving natural convection equations (heat and flow) with the shooting method

TL;DR I've been implementing a python program to solve numerically equations for natural convection based on a particular similarity variable using runge-kutta 4 and the shooting method. However I don't get the right solutions when I plot it. Did I make a mistake somewhere ?
Hi !
Starting from a special case of natural convection, we get these similitude equations.
The first describe the fluid flow, the second describe the heat flow.
"Pr" is for Prandtl it's basically a dimensionless number used in fluid dynamics (Prandtl) :
These equations are subjects to the following boundary values such that the temperature near the plate is greater than the temperature outside the boundary layer and such that the fluid velocity is 0 far away from the boundary layer.
I've been trying to resolve these numerically with Runge-Kutta 4 and the shooting method to transform the boundary value problem into an initial value problem. The way the shooting method is implemented is with the newton method.
However, I don't get the right solutions.
As you can see in the following, the temperature (in red) is increasing as we are moving away from the plate whereas it should decrease exponentially.
It's more consistent for the fluid velocity (in blue), however the speed i think it should go up faster then go down faster. Here the curve is smoother.
Now, the fact is that we have a system of 2 coupled ODE. However, right now, I'm only trying to find the one of the two initials values (e.g. f''(0) = a, trying to find a) such that we have a solution to the boundary value problem (shooting method). Once found, I suppose we have the solution for the whole problem.
I guess I should maybe manage the two (f''(0) = a ; theta'(0) = b) but I don't know how to manage these two in parallel.
Last think to mention, if I try to get the initial value of theta' (so theta'(0)) I don't get the right heat profile.
Here is the code :
"""
The goal is to resolve a 3rd order non-linear ODE for the blasius problem.
It's made of 2 equations (flow / heat)
f''' = 3ff'' - 2(f')^2 + theta
3 Pr f theta' + theta'' = 0
RK4 + Shooting Method
"""
import numpy as np
import math
from scipy.integrate import odeint
from scipy.optimize import newton
from edo_solver.plot import plot
from constants import PRECISION
def blasius_edo(y, t, prandtl):
f = y[0:3]
theta = y[3:5]
return np.array([
# flow edo
f[1], # f' = df/dn
f[2], # f'' = d^2f/dn^2
- 3 * f[0] * f[2] + (2 * math.pow(f[1], 2)) - theta[0], # f''' = - 3ff'' + 2(f')^2 - theta,
# heat edo
theta[1], # theta' = dtheta/dn
- 3 * prandtl * f[0] * theta[1], # theta'' = - 3 Pr f theta'
])
def rk4(eta_range, shoot):
prandtl = 0.01
# initial values
f_init = [0, 0, shoot] # f(0), f'(0), f''(0)
theta_init = [1, shoot] # theta(0), theta'(0)
ci = f_init + theta_init # concatenate two ci
# note: tuple with single argument must have "," at the end of the tuple
return odeint(func=blasius_edo, y0=ci, t=eta_range, args=(prandtl,))
"""
if we have :
f'(t_0) = fprime_t0 ; f'(eta -> infty) = fprime_inf
we can transform it into :
f'(t_0) = fprime_t0 ; f''(t_0) = a
we define the function F(a) = f'(infty ; a) - fprime_inf
if F(a) has a root in "a",
then the solutions to the initial value problem with f''(t_0) = a
is also the solution the boundary problem with f'(eta -> infty) = fprime_inf
our goal is to find the root, we have the root...we have the solution.
it can be done with bissection method or newton method.
"""
def shooting(eta_range):
# boundary value
fprimeinf = 0 # f'(eta -> infty) = 0
# initial guess
# as far as I understand
# it has to be the good guess
# otherwise the result can be completely wrong
initial_guess = 10 # guess for f''(0)
# define our function to optimize
# our goal is to take big eta because eta should approach infty
# [-1, 1] : last row, second column => f'(eta_final) ~ f'(eta -> infty)
fun = lambda initial_guess: rk4(eta_range, initial_guess)[-1, 1] - fprimeinf
# newton method resolve the ODE system until eta_final
# then adjust the shoot and resolve again until we have a correct shoot
shoot = newton(func=fun, x0=initial_guess)
# resolve our system of ODE with the good "a"
y = rk4(eta_range, shoot)
return y
def compute_blasius_edo(title, eta_final):
ETA_0 = 0
ETA_INTERVAL = 0.1
ETA_FINAL = eta_final
# default values
title = title
x_label = "$\eta$"
y_label = "profil de vitesse $(f'(\eta))$ / profil de température $(\\theta)$"
legends = ["$f'(\eta)$", "$\\theta$"]
eta_range = np.arange(ETA_0, ETA_FINAL + ETA_INTERVAL, ETA_INTERVAL)
# shoot
y_set = shooting(eta_range)
plot(eta_range, y_set, title, legends, x_label, y_label)
compute_blasius_edo(
title="Convection naturelle - Solution de similitude",
eta_final=10
)
I could be completely off base here, but I wrote something similar to solve 1D fluid-reaction-heat equations. Try using solve_ivp and using the RADAU solver method, it helps with more difficult systems.
Also maybe try converting your system of ODES to a system of first order ODEs as that may help.
You are implementing the additional but wrong boundary condition f''(0) = theta'(0), as both slots get the same initial value in the shooting method. You need to hold them separate, giving 2 free variables and thus the need for a 2-dimensional Newton method or any other solver for non-scalar functions.
You could just as well use the solve_bvp routine with a sensible initial guess.

Finding the zeroes of a position vector

For my dynamics course I am tasked with writing a python code that will plot the trajectory of a position vector from when it starts on the ground to when it lands on the ground. I currently have my code create a linear space from the two zero values that I calculated by hand, but I want to code that in. Because I also need to create velocity vectors on the trajectory, I have the position vector broken into its x and y components. I have looked into xlim and this thread, but couldn't figure out how to implement them. I'm fairly new to python and coding in general, so I'm still trying to learn how things work.
import numpy as np
import matplotlib.pyplot as plt
#creates a function that returns the x component
def re10(x):
r1 = 0.05*x
return r1
#creates a function that returns the y component
def re20(x):
r2 = -4.91*(x**2) + 30*x + 100
return r2
#Calculates the two zeroes of the trajectory
tmin = (-30 + np.sqrt(30**2 -4*-4.91*100))/(2*-4.91)
tmax = (-30 - np.sqrt(30**2 -4*-4.91*100))/(2*-4.91)
#Initializing time space
t = np.linspace(tmin, tmax, 100)
#Plot
plt.plot(re10(t), re20(t)) #(x, y)
You can easily find the zeroes of a funtion using numpy library.
First, install it. Open a cmd console and write pip install numpy.
Then, write this code in your script:
import numpy
re20 = [-4.91, 30, 100]
zeroes = numpy.roots(coeff)
print(zeroes[0])
print(zeroes[1])
As you will see when running the script from console (or you IDE), numpy.roots(function) will return you the zeroes of your function, as an array.
That is why you use the [] operator to access each one of them (take note that in programming, an array's first element will be at index 0).
To use it directly into your code, you can do:
tmin = zeroes[0]
tmax = zeroes[1]
Simpy is for symbolic operations, it is pretty powerful, but you don't need it for this, my mistake.
Hope you have fun with Python, it's a cool language !

Is there a way to find polygons in given points?

I'm currently working on a way to find rectangles/polygons in up to 15 given points (Image below).
Given Points
My goal is it to find polygons in that point array, like I marked in the image below. The polygons are rectangles in the real world but they are distorted a bit that's the reason why they can look like polygons or other shapes. I must find the best rectangle/polygon.
My idea was to check all connections between the points but the total amount of that is to big to run in and it took.
Does anyone has an idea how to solve that, I researched in the web and found the k-Nearest algorithm in sklearn for python but I don't have experience with that if this is the right way to solve it and how to do that. Maybe I'll also need a method to filter out some of the outliers to make it even easier for the algorithm to find the right corner points of the polygon.
The code snippet below splits the given point string into separate arrays, the array coordinatesOnly contains just the x and y values of the points.
Many thanks for you help.
Polygon in Given Points
import math
import numpy as np
import matplotlib.pyplot as plt
import time
from sklearn.neighbors import NearestNeighbors
millis = round(int(time.time())) / 1000
####input String
print("2D to 3D convert")
resultString = "0,487.50,399.46,176.84,99.99;1,485.93,423.43,-4.01,95.43;2,380.53,433.28,1.52,94.90;3,454.47,397.68,177.07,90.63;4,490.20,404.10,-6.17,89.90;5,623.56,430.52,-176.09,89.00;6,394.66,385.44,90.22,87.74;7,625.61,416.77,-177.95,87.02;8,597.21,591.66,-91.04,86.49;9,374.03,540.89,-11.20,85.77;10,600.51,552.91,178.29,85.52;11,605.29,530.78,-179.89,85.34;12,583.73,653.92,-82.39,84.42;13,483.56,449.58,-91.12,83.37;14,379.01,451.62,-6.21,81.51"
resultString = resultString.split(";")
resultStringSplitted = list()
coordinatesOnly = list()
for i in range(len(resultString)):
resultStringSplitted .append(resultString[i].split(","))
newList = ((float(resultString[i].split(",")[1]),float(resultString[i].split(",")[2])))
coordinatesOnly.append(newList)
for j in range(len(resultStringSplitted[i])):
resultStringSplitted[i][j] = float(resultStringSplitted[i][j])
#Check if score is valid
validScoreList = list()
for i in range(len(resultStringSplitted)):
if resultStringSplitted[i][len(resultStringSplitted[i])-1] != 0:
validScoreList.append(resultStringSplitted[i])
resultStringSplitted = validScoreList
#Result String array contains all 2D results
# [Point Number, X Coordinate, Y Coordinate, Angle, Point Score]
for i in range(len(resultStringSplitted)):
plt.scatter(resultStringSplitted[i][1],resultStringSplitted[i][2])
plt.show(block=True)
Since you mentioned that you can have a maximum of 15 points, I suggest to check all possible combinations of 4 points and keep all rectangles that are close enough to perfect rectangles. For 15 points, it is "only" 15*14*13*12=32760 potential rectangles.
import math
import itertools
import numpy as np
coordinatesOnly = ((0,0),(0,1),(1,0),(1,1),(2,0),(2,1),(1,3)) # Test data
rectangles = []
# Returns True if l0 and l1 are within 10% deviation
def isValid(l0, l1):
if l0 == 0 or l1 == 0:
return False
return abs(max(l0,l1)/min(l0,l1) - 1) < 0.1
for p in itertools.combinations(np.array(coordinatesOnly),4):
for r in itertools.permutations(p,4):
l01 = np.linalg.norm(r[1]-r[0]) # Side
l12 = np.linalg.norm(r[2]-r[1]) # Side
l23 = np.linalg.norm(r[3]-r[2]) # Side
l30 = np.linalg.norm(r[0]-r[3]) # Side
l02 = np.linalg.norm(r[2]-r[0]) # Diagonal
l13 = np.linalg.norm(r[2]-r[0]) # Diagonal
areSidesEqual = isValid(l01,l23) and isValid(l12,l30)
isDiag1Valid = isValid(math.sqrt(l01*l01+l30*l30),l13) # Pythagore
isDiag2Valid = isValid(math.sqrt(l01*l01+l12*l12),l02) # Pythagore
if areSidesEqual and isDiag1Valid and isDiag2Valid:
rectangles.append(r)
break
print(rectangles)
It takes about 1 second to run on 15 points on my computer. It really depends on what are your requirements for computation time, i.e., real time, interactive time, "I just don't want to spend days waiting for the answer" time.

How to reshape a networkx graph in Python?

So I created a really naive (probably inefficient) way of generating hasse diagrams.
Question:
I have 4 dimensions... p q r s .
I want to display it uniformly (tesseract) but I have no idea how to reshape it. How can one reshape a networkx graph in Python?
I've seen some examples of people using spring_layout() and draw_circular() but it doesn't shape in the way I'm looking for because they aren't uniform.
Is there a way to reshape my graph and make it uniform? (i.e. reshape my hasse diagram into a tesseract shape (preferably using nx.draw() )
Here's what mine currently look like:
Here's my code to generate the hasse diagram of N dimensions
#!/usr/bin/python
import networkx as nx
import matplotlib.pyplot as plt
import itertools
H = nx.DiGraph()
axis_labels = ['p','q','r','s']
D_len_node = {}
#Iterate through axis labels
for i in xrange(0,len(axis_labels)+1):
#Create edge from empty set
if i == 0:
for ax in axis_labels:
H.add_edge('O',ax)
else:
#Create all non-overlapping combinations
combinations = [c for c in itertools.combinations(axis_labels,i)]
D_len_node[i] = combinations
#Create edge from len(i-1) to len(i) #eg. pq >>> pqr, pq >>> pqs
if i > 1:
for node in D_len_node[i]:
for p_node in D_len_node[i-1]:
#if set.intersection(set(p_node),set(node)): Oops
if all(p in node for p in p_node) == True: #should be this!
H.add_edge(''.join(p_node),''.join(node))
#Show Plot
nx.draw(H,with_labels = True,node_shape = 'o')
plt.show()
I want to reshape it like this:
If anyone knows of an easier way to make Hasse Diagrams, please share some wisdom but that's not the main aim of this post.
This is a pragmatic, rather than purely mathematical answer.
I think you have two issues - one with layout, the other with your network.
1. Network
You have too many edges in your network for it to represent the unit tesseract. Caveat I'm not an expert on the maths here - just came to this from the plotting angle (matplotlib tag). Please explain if I'm wrong.
Your desired projection and, for instance, the wolfram mathworld page for a Hasse diagram for n=4 has only 4 edges connected all nodes, whereas you have 6 edges to the 2 and 7 edges to the 3 bit nodes. Your graph fully connects each "level", i.e. 4-D vectors with 0 1 values connect to all vectors with 1 1 value, which then connect to all vectors with 2 1 values and so on. This is most obvious in the projection based on the Wikipedia answer (2nd image below)
2. Projection
I couldn't find a pre-written algorithm or library to automatically project the 4D tesseract onto a 2D plane, but I did find a couple of examples, e.g. Wikipedia. From this, you can work out a co-ordinate set that would suit you and pass that into the nx.draw() call.
Here is an example - I've included two co-ordinate sets, one that looks like the projection you show above, one that matches this one from wikipedia.
import networkx as nx
import matplotlib.pyplot as plt
import itertools
H = nx.DiGraph()
axis_labels = ['p','q','r','s']
D_len_node = {}
#Iterate through axis labels
for i in xrange(0,len(axis_labels)+1):
#Create edge from empty set
if i == 0:
for ax in axis_labels:
H.add_edge('O',ax)
else:
#Create all non-overlapping combinations
combinations = [c for c in itertools.combinations(axis_labels,i)]
D_len_node[i] = combinations
#Create edge from len(i-1) to len(i) #eg. pq >>> pqr, pq >>> pqs
if i > 1:
for node in D_len_node[i]:
for p_node in D_len_node[i-1]:
if set.intersection(set(p_node),set(node)):
H.add_edge(''.join(p_node),''.join(node))
#This is manual two options to project tesseract onto 2D plane
# - many projections are available!!
wikipedia_projection_coords = [(0.5,0),(0.85,0.25),(0.625,0.25),(0.375,0.25),
(0.15,0.25),(1,0.5),(0.8,0.5),(0.6,0.5),
(0.4,0.5),(0.2,0.5),(0,0.5),(0.85,0.75),
(0.625,0.75),(0.375,0.75),(0.15,0.75),(0.5,1)]
#Build the "two cubes" type example projection co-ordinates
half_coords = [(0,0.15),(0,0.6),(0.3,0.15),(0.15,0),
(0.55,0.6),(0.3,0.6),(0.15,0.4),(0.55,1)]
#make the coords symmetric
example_projection_coords = half_coords + [(1-x,1-y) for (x,y) in half_coords][::-1]
print example_projection_coords
def powerset(s):
ch = itertools.chain.from_iterable(itertools.combinations(s, r) for r in range(len(s)+1))
return [''.join(t) for t in ch]
pos={}
for i,label in enumerate(powerset(axis_labels)):
if label == '':
label = 'O'
pos[label]= example_projection_coords[i]
#Show Plot
nx.draw(H,pos,with_labels = True,node_shape = 'o')
plt.show()
Note - unless you change what I've mentioned in 1. above, they still have your edge structure, so won't look exactly the same as the examples from the web. Here is what it looks like with your existing network generation code - you can see the extra edges if you compare it to your example (e.g. I don't this pr should be connected to pqs:
'Two cube' projection
Wikimedia example projection
Note
If you want to get into the maths of doing your own projections (and building up pos mathematically), you might look at this research paper.
EDIT:
Curiosity got the better of me and I had to search for a mathematical way to do this. I found this blog - the main result of which being the projection matrix:
This led me to develop this function for projecting each label, taking the label containing 'p' to mean the point has value 1 on the 'p' axis, i.e. we are dealing with the unit tesseract. Thus:
def construct_projection(label):
r1 = r2 = 0.5
theta = math.pi / 6
phi = math.pi / 3
x = int( 'p' in label) + r1 * math.cos(theta) * int('r' in label) - r2 * math.cos(phi) * int('s' in label)
y = int( 'q' in label) + r1 * math.sin(theta) * int('r' in label) + r2 * math.sin(phi) * int('s' in label)
return (x,y)
Gives a nice projection into a regular 2D octagon with all points distinct.
This will run in the above program, just replace
pos[label] = example_projection_coords[i]
with
pos[label] = construct_projection(label)
This gives the result:
play with r1,r2,theta and phi to your heart's content :)

Categories