Little new here and any help would be appreciated.
I have been tooling around with this code for a while now and I cant seem to wrap my head around it. Im fairly new to python so I dont quite know or remember all the tricks yet/skills.
So the question at hand:
Equation: {x_(n+1) = x_n * r * (1- x_n)}
With x_n between (0,1) and r between (0,4).
The goal here is to make a loop function that will gather a value for 'x_n' and 'r' and spit out the iteration 'n' and the current 'x_n+1'; i.e. print(n , x_n+1), at each 'n' step while checking to see if the new value is within 0.0000001 of the old value.
If it settles on a fixed point within 20,000 (0.0000001), print the final 'n' + message. If not then and goes to 20,000 then print another message.
All i have so far is:
import math
x_o=float(input("Enter a 'seed' value: "))
r=float(input("Enter an 'r' value: "))
x_a=((x_o + 0) * r * (1-(x_o + 0)))
while x_a != (0.0000001, x_o , 0.0000001):
for n in range(0,99):
x_a=((x_o + n) * r * (1-(x_o + n)))
print(n , x_a)
I'm pretty sure this is no where close so any help would be awesome; if you need any more info let me know.
Much appreciated,
Genosphere
You could write a generator function and use it directly in your for loop. If you need to keep track of the rank of intermediate values you can use enumerate on the generator.
def fnIter(fn,x,delta=0.000001):
while True:
yield x
prev,x = x,fn(x)
if abs(x-prev)<delta:break
output:
r = 2
seed = 0.1
for i,Xn in enumerate(fnIter(lambda x:x*r*(1-x),seed)):
print(i,Xn)
0 0.1
1 0.18000000000000002
2 0.2952
3 0.41611392
4 0.4859262511644672
5 0.49960385918742867
6 0.49999968614491325
7 0.49999999999980305
To implement the maximum iteration check you can either add a conditional break in the loop or use zip with a range:
maxCount = 20000
n,Xn = max(zip(range(maxCount+1),fnIter(lambda x:x*r*(1-x),seed)))
if n < maxCount:
print(n,Xn)
else:
print(Xn,"not converging")
This is an exponentially-weighted moving average. Pandas has a function for this: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.ewm.html
You have a good start so far. You might be overthinking it, though.
The following approach just tries to generate this sequence for 20,000 terms. Each time, it checks whether the new value is within 0.0000001 from the previous value. If so, it breaks out of the loop and prints that. If not, it uses python's for/else construct to print a different value. Note the different levels of indentation.
x_0 = float(input("enter a 'seed' value: "))
r = float(input("enter an 'r' value: "))
x_m = x_0 # placeholder for 'previous value'
delta = 0.0000001
# Try to calculate 20 thousand terms of this sequence
# We will break out of the loop early if our x_n converges
for _ in range(20000):
x_n = x_m * r * (1 - x_m)
if abs(x_n - x_m) < delta:
print("Settled on value for x_n: ", x_n)
break
else:
x_m = x_n # move forward to the next value
else:
print("x_n did not converge in 20000 terms")
Related
I want to draw a triangle of asterisks from a given n which is an odd number and at least equal to 3. So far I did the following:
def main():
num = 5
for i in range(num):
if i == 0:
print('-' * num + '*' * (i + 1) + '-' * num)
elif i % 2 == 0:
print('-' * (num-i+1) + '*' * (i + 1) + '-' * (num-i+1))
else:
continue
if __name__ == "__main__":
main()
And got this as the result:
-----*-----
----***----
--*****--
But how do I edit the code so the number of hyphens corresponds to the desirable result:
-----*-----
----***----
---*****---
--*-----*--
-***---***-
*****-*****
There's probably a better way but this seems to work:
def triangle(n):
assert n % 2 != 0 # make sure n is an odd number
hyphens = n
output = []
for stars in range(1, n+1, 2):
h = '-'*hyphens
s = '*'*stars
output.append(h + s + h)
hyphens -= 1
pad = n // 2
mid = n
for stars in range(1, n+1, 2):
fix = '-'*pad
mh = '-'*mid
s = '*'*stars
output.append(fix + s + mh + s + fix)
pad -= 1
mid -= 2
print(*output, sep='\n')
triangle(5)
Output:
-----*-----
----***----
---*****---
--*-----*--
-***---***-
*****-*****
Think about what it is you're iterating over and what you're doing with your loop. Currently you're iterating up to the maximum number of hyphens you want, and you seem to be treating this as the number of asterisks to print, but if you look at the edge of your triforce, the number of hyphens is decreasing by 1 each line, from 5 to 0. To me, this would imply you need to print num-i hyphens each iteration, iterating over line number rather than the max number of hyphens/asterisks (these are close in value, but the distinction is important).
I'd recommend trying to make one large solid triangle first, i.e.
-----*-----
----***----
---*****---
--*******--
-*********-
***********
since this is a simpler problem to solve and is just one modification away from what you're trying to do (this is where the distinction between number of asterisks and line number will be important, as your pattern changes dependent on what line you're on).
I'll help get you started; for any odd n, the number of lines you need to print is going to be (n+1). If you modify your range to be over this value, you should be able to figure out how many hyphens and asterisks to print on each line to make a large triangle, and then you can just modify it to cut out the centre.
I have multiple ranges lets say 1-1000, 1000-2000, 2000-3000, 3000-4000, 4000-5000. I get a number from the user and now i need to find in which range it lies. One way to do this would be to create multiple if statement and check from there like so:
if num>=1 and num < 1000:
print "1"
elif num >=1000 and num < 2000:
print "2"
....
This method would create a lot of branches.
Is there an optimized way to do this without so many branches and in the least complexity?
PS: I just wrote the code in python since its shorter to write but this can be case in any language. Also the range and output can be very different.
The range and output are examples and can be anything like 1-100, 100-1000, 1000-1500 etc and output like "Very Low, low, medium" something like that.
Store the starting or ending of the range in the list and sort it along with number to find its exact range.
import numpy as np
start = [1,1000,2000,3000,4000]
print(list(np.sort(start+[num])).index(num))
If your ranges don't follow any particular logic, there's not much you can do except testing them one by one, but you can still simplify the code by using a loop:
ranges = [[0,1000],[1500,1600],[1200,1220]]
def find_range(num, ranges)
for low, high in ranges:
if low <= num < high:
return low, high # or any other formating using a dict for example
Of course you can optimize a bit by sorting your ranges and then doing a binary search instead of linear...
my_range=(1,1000), (1000,2000), (2000,3000), (3000,4000), (4000,5000)
my_output='Very Low, Low, Medium, High, Very High'.split(', ')
num=3565
for k,i in enumerate(my_range):
if i[0]<=num<i[1]:print(my_output[k]);break
else:
print('Out of range')
How about something like this:
ranges = {
0: 'undefined range',
1000: '1',
1500: '2',
2500: '3'
}
num = 500
print(ranges[max(ranges, key=lambda x: num < x)])
Output: 1
Suspect that you have many breaks and require an optimized search, you can go with bisection on an ordered list of breakpoints resulting in a logarithmic time consumption:
import random
import time
def split_pivot(intervals, number):
"""Divide and conquer recursively."""
if len(intervals) == 1:
return intervals[0]
if len(intervals) == 2:
if number >= intervals[1][1][0]:
return intervals[1]
elif number < intervals[0][1][1]:
return intervals[0]
else:
raise
pivot = int(len(intervals) // 2.0)
if number < intervals[pivot][1][1]:
return split_pivot(intervals[:pivot + 1], number)
elif number >= intervals[pivot + 1][1][0]:
return split_pivot(intervals[pivot + 1:], number)
else:
raise
if __name__ == '__main__':
UPPER_BOUND = 10000000
newbreak = 0
manybreaks = []
while newbreak < UPPER_BOUND:
step = int(random.random() * 10) + 1
manybreaks.append(newbreak + step)
newbreak = manybreaks[-1]
print('Breaks: {:d}'.format(len(manybreaks)))
intervals = [
(idx, (manybreaks[idx], manybreaks[idx + 1]))
for idx in range(len(manybreaks) - 1)
]
print('Intervals: {:d}'.format(len(intervals)))
print(
' Example: idx {tpl[0]:d}, lower {tpl[1][0]:d}, upper {tpl[1][1]:d}'
.format(tpl=random.choice(intervals)))
thenumber = int(random.random() * UPPER_BOUND)
print('Number: {:d}'.format(thenumber))
t0 = time.time()
result = split_pivot(intervals, thenumber)
t1 = time.time()
print('Result: {e[0]:d} ({e[1][0]:d}, {e[1][1]:d})'.format(e=result))
print(' Done in {:.4f}s'.format(t1 - t0))
The result of the search itself is (on my machine) below 0.05 seconds. The generation of breakpoints and corresponding intervals runs for roughly 4.5 seconds:
Breaks: 1818199
Intervals: 1818198
Example: idx 605849, lower 3330441, upper 3330446
Number: 6951844
Result: 1263944 (6951843, 6951847)
Done in 0.0436s
maybe just divide by 1000 and take the entire part :
here example in python :
>>> x=3608
>>> int(x/1000+1)
4
Following your comment/edit in your post, if you need a different output (a string for example) you can (in python) use a dict :
>>> Output={'1': 'very low', '2': 'low', '3': 'medium','4':'high' }
>>> x=2954
>>> Output[str(int(x/1000+1))]
'medium'
I am doing the Project Euler #67 in Python. My program, which worked for Project 18, does not work for Project 67.
Code (excludes the opening of the file and the processing of information):
for i in range(len(temp)):
list1 = temp[i]
try:
list2 = temp[i+1]
trynum1 = list1[lastinput] + max(list2[lastinput],list2[lastinput+1])
try:
trynum2 = list1[lastinput+1] + max(list2[lastinput+1],list2[lastinput+2])
if trynum1 > trynum2:
outputlist.append(list1[lastinput])
else:
outputlist.append(list1[lastinput+1])
lastinput += 1
except IndexError:
outputlist.append(list1[0])
except IndexError:
if list1[lastinput] > list1[lastinput+1]:
outputlist.append(list1[lastinput])
else:
outputlist.append(list1[lastinput+1])
Variables:
temp is the triangle of integers
outputlist is a list which stores the numbers chosen by the program
I know the answer is 7273, but my program finds 6542. I cannot find an error which causes the situation. Please may you help me on it.
Logic
My approach to this program is to find one number (list1[lastinput]) and add it up with the larger number of the two below it (trynum1), compare with the number to the right of the first number (list1[lastinput+1]), adding the larger number of two below it (trynum2). I append the larger one to the output list.
This approach is logically flawed. When you're in row 1, you don't have enough information to know whether moving right or left will lead you to the largest sum, not with only a 2-row lookahead. You would need to look all the way to the bottom to ensure getting the best path.
As others have suggested, start at the bottom and work up. Remember, you don't need the entire path, just the sum. At each node, add the amount of the better of the two available paths (that's the score you get in taking that node to the bottom). When you get back to the top, temp[0][0], that number should be your final answer.
I thought day and night about problem 18 and I solved it, the same way I solved this one.
P.S. 100_triangle.txt is without 1st string '59'.
# Maximum path sum II
import time
def e67():
start = time.time()
f=open("100_triangle.txt")
summ=[59]
for s in f:
slst=s.split()
lst=[int(item) for item in slst]
for i in range(len(lst)):
if i==0:
lst[i]+=summ[i]
elif i==len(lst)-1:
lst[i]+=summ[i-1]
elif (lst[i]+summ[i-1])>(lst[i]+summ[i]):
lst[i]+=summ[i-1]
else:
lst[i]+=summ[i]
summ=lst
end = time.time() - start
print("Runtime =", end)
f.close()
return max(summ)
print(e67()) #7273
Though starting from the bottom is more efficient, I wanted to see if I could implement Dijkstra's algorithm on this one; it works well and only takes a few seconds (didn't time it precisely):
from math import inf
f = open("p067_triangle.txt", "r")
tpyramid = f.read().splitlines()
f.close()
n = len(tpyramid)
pyramid = [[100 - int(tpyramid[i].split()[j]) for j in range(i+1)] for i in range(n)]
paths = [[inf for j in range(i+1)] for i in range(n)]
paths[0][0] = pyramid[0][0]
def mini_index(pyr):
m = inf
for i in range(n):
mr = min([i for i in pyr[i] if i >= 0]+[inf])
if mr < m:
m, a, b = mr, i, pyr[i].index(mr)
return m, a, b
counter = 0
omega = inf
while counter < n*(n+1)/2:
min_weight, i, j = mini_index(paths)
if i != n-1:
paths[i+1][j] = min( paths[i+1][j], min_weight + pyramid[i+1][j])
paths[i+1][j+1] = min( paths[i+1][j+1], min_weight + pyramid[i+1][j+1])
else:
omega = min(omega, min_weight)
paths[i][j] = -1
counter += 1
print(100*n - omega)
Here is my solution. Indeed you have to take the bottom - up approach.
Result confirmed with PE. Thanks!
def get_triangle(listLink):
triangle = [[int(number) for number in row.split()] for row in open(listLink)]
return triangle
listOfLists = get_triangle('D:\\Development\\triangle.txt')
for i in range(len(listOfLists) - 2, -1, -1):
for j in range(len(listOfLists[i])):
listOfLists[i][j] += max(listOfLists[i+1][j], listOfLists[i+1][j+1])
print(listOfLists[0][0])
I have designed a code which will take a 'number' as an input from the user.
The number will be used to make a...
numerator = (3*number) - 2
and a denominator, which will be denominator = (4*n) + 1.
The code will also allow the user to choose how many times they want this sequence to go on after which the sum of all the fractions will be totaled and displayed.
Here is the Code I have:
l=int(input("How many times do you repeat this sequence?: "))
n=int(input("Enter a base number: "))
n1=n
n2=n
total=0
s = ''
def calculate(l,n,n1,n2,total,s):
for j in range(l):
s += "{}/{} + ".format(3*n1-2, 4*n2+1)
n1=n+n1
n2=n+n2
total=(((n*3)-2)/((4*n)+1))+total
print(s)
print(total)
calculate(l, n, n1, n2, total, s)
Now here are the two errors that I receive when I get the output for this code for example:
How many times do you repeat this sequence?: 2
Enter a base number: 1
1/5 + 4/9 +
0.4
The two Issues:
Since 4/9 is the last fraction, is there a way to get rid of that "+" addition sign at the end, because it just points to a blank space..
The total for the two fractions shows to be 0.4 which is incorrect, the total sum should be 1/5 + 4/9 = 0.2 + 0.44 = 0.64, I am unsure where I went astray when inputting my total sum formula above.
Any suggestions/comments would be appreciated!
A cheap way of removing the + would be to simply cut off the last character in the string: str[:-1].
As far a issue 2 goes, it looks like you want to use n1 and n2 instead of n.
As of now, you're getting 1/5(.2) + 1/5(.2) = .4
Instead of concatening a string like that, collect all the parts in a list and then join the items on the plus sign:
s = []
s.append('{}/{}'.format(1, 5))
s.append('{}/{}'.format(4, 9))
print(' + '.join(s)) # 1/5 + 4/9
I’m not really sure what you are doing but if you want to get the sum of the fractions you print, you should just make sure that you calculate those individual fractions in the same way. So instead of incrementing n1 and n2 first before calculating the sum, calculate the sum in the same way you did for the fraction output and only afterwards change those variables:
s.append("{}/{}".format(3 * n1 - 2, 4 * n2 + 1))
total += (3 * n1 - 2) / (4 * n2 + 1)
n1 += n
n2 += n
I dont know python but you could do the following to correct your logical errors.
to remove the '+' at the end, you can do something like below,
if j = l (implies last fraction)
dont include +
else
include +
While calculating total you are using 'n' value which always remains as your input value
total=(((n*3)-2)/((4*n)+1))+total
Here use n1 or n2
total=(((n1*3)-2)/((4*n2)+1))+total
My goal is to make a program that takes an input (Battery_Capacity) and ultimately spits out a list of the (New_Battery_Capacity) and the Number of (Cycle) it takes for it ultimately to reach maximum capacity of 80.
Cycle = range (160)
Charger_Rate = 0.5 * Cycle
Battery_Capacity = float(raw_input("Enter Current Capacity:"))
New_Battery_Capacity = Battery_Capacity + Charger_Rate
if Battery_Capacity < 0:
print 'Battery Reading Malfunction (Negative Reading)'
elif Battery_Capacity > 80:
print 'Battery Reading Malfunction (Overcharged)'
elif float(Battery_Capacity) % 0.5 !=0:
print 'Battery Malfunction (Charges Only 0.5 Interval)'
while Battery_Capacity >= 0 and Battery_Capacity < 80:
print New_Battery_Capacity
I was wondering why my Cycle = range(160) isn't working in my program?
Your first problem is that you have the first two lines in the wrong order. You need a "Cycle" variable to exist before you can use it.
You'll still get an error when you swap them, though. You can't multiply a list by a float. A list comprehension is more what you want:
Charger_Rate = [i * .5 for i in Cycle]
As far as I can tell, the range(160) part is fine.