Why does my code not seem random? - python

I'm trying to create a basic code to simulate stock market behavior as an exercise in my programming class. It's based off of weighted randomness and is displayed through pylab.
For the most part it looks good, but for no matter how many trials I run there seems to be a tad that does not look random. From 1-50 of each random update, there seems to be a definitive upwards trend that is not reflected anywhere else in the series. The weighted values are not altered anywhere else in the code, so this trend should be an aberration seeing that I make sure that the results given are the average of a great many trials. Would anyone know what's wrong with my code that causes this to happen? Thanks!
class Simulation(object):
def __init__(self, netPos=300, downChance=.1, downTrend=.06, start = 1285.85, time = 0, recession = False):
self.netPos = netPos
self.downChance = downChance
self.downTrend = downTrend
self.value = start
self.time = time
self.recession = False
def getValue(self):
return self.value
def update(self):
if not self.recession:
if random.random() < self.downTrend:
self.recession = True
if random.random() > self.downChance:
self.value += random.random() * self.netPos
else:
self.value -= random.random() * self.netPos
else:
if random.random() < self.downTrend:
self.recession = False
if random.random() < self.downChance:
self.value += random.random() * self.netPos
else:
self.value -= random.random() * self.netPos
times = 5000
values = []
for i in range(1200):
values += [0]
for x in range(times):
runOnce = Simulation()
for y in range(1200):
values[y] += runOnce.getValue()
runOnce.update()
for i in range(1200):
values[i] = values[i] / times
def plottem(x,y):
pylab.plot(range(1200), values[x:y-1], label="Trend")
pylab.title("Simulated Trend")
pylab.xlabel("Time")
pylab.ylabel("Relative Value")
pylab.legend(loc = 1)
pylab.show()
def getChange(x,y):
print (values[x] - values[y-1])/(x-y-1)
plottem(0,1999)
Results:

This is entirely expected. You've run a bunch of simulations that all start with an upward trend and averaged their results. Since they all start with an uptick, the average starts with an uptick. After that, they go out of phase, and the average doesn't have much of a trend.

Related

What is the difference between the following seemingly same two python functions?

I'm new to data structures and algorithms, so I was kind of confused when I was writing a function to find a pair of numbers from two arrays (one from each array) that the absolute value of difference of the two numbers is the smallest. My first draft was version 2, but it did not pass all the tests. However, when I assigned arrayOne[i] to firstNum and arrayTwo[j] to secondNum, it passed all the test cases. Could anyone explain what happened exactly? Since I thought these two versions were exactly the same.
Version 1:
def smallestDifference(arrayOne, arrayTwo):
arrayOne.sort()
arrayTwo.sort()
i = j = 0
smallest = float('inf')
current = float('inf')
smallestPair = []
while i < len(arrayOne) and j < len(arrayTwo):
firstNum = arrayOne[i]
secondNum = arrayTwo[j]
if firstNum < secondNum:
current = abs(firstNum - secondNum)
i += 1
elif firstNum > secondNum:
current = abs(firstNum - secondNum)
j += 1
else:
return [firstNum, secondNum]
if current < smallest:
smallest = current
smallestPair = [firstNum, secondNum]
return smallestPair
Version 2:
def smallestDifference(arrayOne, arrayTwo):
arrayOne.sort()
arrayTwo.sort()
i = j = 0
smallest = float('inf')
current = float('inf')
smallestPair = []
while i < len(arrayOne) and j < len(arrayTwo):
if arrayOne[i] < arrayTwo[j]:
current = abs(arrayOne[i] - arrayTwo[j])
i += 1
elif arrayOne[i] > arrayTwo[j]:
current = abs(arrayOne[i] - arrayTwo[j])
j += 1
else:
return [arrayOne[i], arrayTwo[j]]
if current < smallest:
smallest = current
smallestPair = [arrayOne[i], arrayTwo[j]]
return smallestPair
In version 1, you are indexing arrayOne and arrayTwo for your first if,elif,else statement which is fine, however you change the value of i/j so if the program hits the if current < smallest part of the algorithm, the value of i/j has changed.
For example lets say i and j where both 0 and arrayOne[0] < arraytwo[0], you would increment i and continue on. Once you get to the bottom and you want to delclare smallestPair, you are now setting the value to [arrayOne[1], arrayTwo[0] rather than [arrayOne[0], arrayTwo[0] because you incremented i.
Version one declares the two variables and uses those declarations for the WHOLE function.

Majority tree evaluation

Consider a complete ternary tree of depth h, composed of a root attached to three complete ternary trees of depth h - 1. There are n = 3^h leaves and each leaf has a boolean value associated to it. Each internal node, including the root, equals the value of the majority of its children.
Here is an example of a tree of depth 2:
Given the leaves input vector [0, 0, 1, 0, 1, 0, 1, 1, 1], we would like to find the root of the tree. In order to find the root, we could evaluate all the leaves and internal nodes (i.e. 3^h operations). But we may be able to evaluate fewer nodes. In the example above, we can see that the value of the first internal node (most left) can be evaluated after examining its first two children. Similarly at depth = 1, the first two nodes are sufficient to find the root of the tree.
I have been thinking over this problem but I can't find a good way to tackle the problem.
import numpy as np
import random
class node:
def __init__(self):
self.low = None
self.mid = None
self.high = None
def put(self, low, mid, high):
self.low = low
self.mid = mid
self.high = high
return self
class ternary_tree:
def __init__(self, leaves, count= 0):
self.leaves = leaves
self.root = node()
self.value = None
self.count = count
def get_root(self):
self.root.put(self.leaves[0], self.leaves[1], self.leaves[2])
self.value = majority(self.root)
return self.value
def majority(node):
global ops_count
r1, r2, r3 = random.sample([node.low, node.mid, node.high], 3)
if r1 > 0:
ops_count += 1
if r2 > 0:
ops_count += 1
return 1;
elif r3 > 0:
ops_count += 1
return 1;
else:
return 0;
else:
ops_count += 1
if r2 == 0:
ops_count += 1
return 0;
elif r3 == 0:
ops_count += 1
return 0;
else:
return 1;
if __name__ == "__main__":
h = 2 # depth of the tree
my_leaves = [random.randint(0,1) for i in range(0, 3**h)] #input vector
ops_count = 0 #Counting the number of steps
nb_trees = len(my_leaves) // 3
my_trees = [ternary_tree(leaves=my_leaves[i:i+3]) for i in range(0, nb_trees)]
new_leaves = []
t1, t2, t3 = random.sample(my_trees, 3)
new_leaves.append(t1.get_root())
new_leaves.append(t2.get_root())
if new_leaves[0] == new_leaves[1]:
new_leaves.append(new_leaves[0])
else:
new_leaves.append(t3.get_root())
ternary_tree(leaves=new_leaves).get_root()
I think the code does the job, but it is not optimal in the sense that it still checks all the internal node and doesn't skip the redundant nodes. I think the right approach is to have a recursive algorithm like a binary search tree, but I cannot make the link between BST and the majority tree evaluation.
I would appreciate if you could give me any indication on how to solve this problem. Thanks!
The illustration comes from here: http://www.math.ucsd.edu/~gptesler/188/MajTree/majtree.html.
Indeed, recursion would be the way to find the root value. I don't really see a need to create the tree data structure: when the values of all the leaf values are input as a list, then we really have all information in a suitable format.
Here is how the majority function could look when it is given only the list of leaf values:
import random
def majority(leaves):
counter = 0
def recur(start, size):
nonlocal counter
if size == 1:
counter += 1 # about to access a leaf's value
return leaves[start]
size //= 3
# Randomly choose which child we will leave as "plan B" in case
# two others give opposite values
last = random.randint(0, 2)
# Get the values of the two other children, using recursion
val1 = recur(start + ((last+1)%3)*size, size)
val2 = recur(start + ((last+2)%3)*size, size)
# If equal, we do not need to retrieve the remaining child's value
if val1 == val2:
return val1
# Too bad,... we need the value of the third child to break the tie
return recur(start + last*size, size)
rootval = recur(0, len(leaves))
return rootval, counter
You would call it like this:
h = 2
leaves = [random.randint(0,1) for i in range(0, 3**h)]
rootval, counter = majority(leaves)
print("The leaves are {}".format(leaves))
print("Accessed {} leaves to find that root's value is {}".format(counter, rootval))

How to determine the complexity of python code?

I need to understand the complexity of the following code. I am familiar with the concepts of all the Big O() notation and also have read a lot of blogs but I cant figure how to apply to big programs.
Following is the code for largest pallindrome number from 100 to 999:
def isPaindrome(number):
stringNum = str(number)
firstDigit_index,lastDigit_index=0,len(stringNum)-1
isPalindrome = False
while(lastDigit_index > 0 and firstDigit_index < lastDigit_index):
#print(stringNum[f],"==",stringNum[l],"......")
if(stringNum[firstDigit_index]==stringNum[lastDigit_index]):
isPalindrome = True
else:
isPalindrome = False
break
firstDigit_index = firstDigit_index + 1
lastDigit_index = lastDigit_index - 1
if(isPalindrome):
return number
else:
return 0
max = 0
startRange = 100
endRange = 999
for i in range(endRange*endRange,startRange*startRange,-1):
factors = []
result = isPaindrome(i)
if(result!=0):
for i in range(startRange,endRange+1):
if(result%i==0):
factors.append(i)
if(len(factors)>1):
sumFactor = factors[(len(factors))-1] + factors[(len(factors))-2]
mul = factors[(len(factors))-1] * factors[(len(factors))-2]
if(sumFactor>max and mul==result):
max = sumFactor
print("Largest Palindrome made from product of two 3 digit numbers(",factors[(len(factors))-1],",",factors[(len(factors))-2] ,") is", result,".")
If anyone could just make me understant step by step how to calculate I'd be grateful.
As I mentioned, your isPalindrome function is literally incorrect, as you're not changing the indexes. I changed a bit of your also, so this is the version I'm analysing. (I'm only analysing the isPalindrome function, since I actually couldn't understand what the main function is doing), sorry!
def isPalindrome(n):
num = str(n)
head, tail = 0, len(num) - 1
while tail > head:
if num[head] != num[tail]: # Not symmetrical!! WARNING!
return False
head += 1 # move position
tail -= 1 # move position
return True
This code on average is O(|n|) i.e. O(log N) where N is the number. This is because on average, the if comparison has 50% chance of breaking (returning False) and 50% of continuing. Therefore the expected number of comparisons would be |n|/4 which is O(|n|).

Hofstadter equation related code in python

There was this question in a university assignment related to Hofstadter sequence. It basically say that it is a integer sequence blah blah and there are two values for a given index n. A male value [M(n)] and a female value [F(n)].
They are defined as:
M(0)=0
F(0)=1
M(n)=n-F(M(n-1))
F(n)=n-M(F(n-1))
And we were asked to write a program in python to find the Male and Female values of the sequence of a given integer.
So the code I wrote was:
def female(num):
if num == 0:
return 1
elif num >0:
return num - male(female(num-1))
def male(num):
if num==0:
return 0
elif num >0:
return num - female(male(num-1))
And when executed with a command like
print male(5)
It works without a fuss. But when I try to find the value of n = 300, the program gives no output.
So I added a print method inside one of the functions to find out what happens to the num value
[ elif num>0:
print num ...]
And it shows that the num value is decreasing until 1 and keeps hopping between 1 and 2 at times reaching values like 6.
I can’t figure out why it happens. Any insight would be nice. Also what should I do to find the values relevant to bigger integers. Thanks in advance. Cheers.
The code is theoretically fine. What you underestimate is the complexity of the computation. Formula
M(n)=n-F(M(n-1))
actually means
tmp = M(n-1)
M(n) = n - F(tmp)
So if you represent this calculation as a tree of necessary calls, you might see that its a binary tree and you should go through all its nodes to calculate the results. Given that M(n) and F(n) are about n/2 I'd estimate the total number of the nodes to be of order 2^(n/2) which becomes a huge number once you put n = 300 there. So the code works but it just will take a very very long time to finish.
The one way to work this around is to employ caching in a form of memoization. A code like this:
femCache = dict()
def female(num):
#print("female " + str(num))
global femCache
if num in femCache:
return femCache[num];
else:
res = 1 # value for num = 0
if num > 0:
res = num - male(female(num-1))
femCache[num] = res
return res
maleCache = dict()
def male(num):
#print("male " + str(num))
global maleCache
if num in maleCache:
return maleCache[num];
else:
res = 0 # value for num = 0
if num > 0:
res = num - female(male(num-1))
maleCache[num] = res
return res
print(male(300))
should be able to compute male(300) in no time.

def getLotteryGame(): won't return(True)

In my def getLotteryGame(): Which is suppose to check if the timer runs out and if it does it sorts the players, ranks them, gives them their winnings and stores a note for them and then return True and when it returns True the bot reloads the game making a new round. I tried several ways of trying to get it to return True. This is the code:
def getLotteryGame():
global pot
global players
different = float(time.time() - lotteryStart)
years = int(different / Point.YEAR)
days = int((different % Point.YEAR) / Point.DAY)
hours = int((different % Point.DAY) / Point.HOUR)
mins = int((different % Point.HOUR) / Point.MINUTE)
secs = int(different % Point.MINUTE)
if secs <= 0:
if len(players) > 0:
random.shuffle(players)
ratios = []
for i in range(-2, len(players) - 2) if i > 0 else range(len(players)):
if i < 0:
ratios.append(1 - (i * 0.33)) # ratio > 1
else:
ratios.append(1 / (1 + (i * 0.33))) # ratio <= 1
winnings = [pot * r for r in ratios]
for m in range(1, len(players)):
notes.store("~lottery~", players[m], "The system has placed you "+Point.ordinal(m)+" in the lottery. The lottery awarded you "+winnings+" P$", time.time())
alerts.append(players[m])
winnings = int(winnings)
point = Point.dPoint[players[m]]
point = int(point)
point = int(point+winnings)
Point.dPoint[players[m]] = int(point)
return(True)
elif len(players) == 0:
return(True)
else:
return(False)
When I wait for the difference to go <= 0 for if secs <= 0. It keeps returning False instead and I'm not sure why.
Your code logic is brokem. lotteryStart is defined when the code first runs, as time.time(). Later, you find the number of seconds since lotteryStart. This number of seconds, might be zero occasionally, and is never going to be less than zero. Since time moves forward, it should always be positive. Thus your code always executes the final else statement that returns False.
different = float(time.time() - lotteryStart)
Maybe lotteryStart is a global variable as well as it is not defined anywhere?

Categories

Resources