Function "Interval_point" - python

I have a task for my pyton101 course at uni which is as follows:
Create a function interval_point(a, b, x) that takes three numbers and interprets a and b as the start and end point of an interval, and x as a fraction between 0 and 1 that determines how far to go towards b, starting at a.
Examples (IPython):
In [ ]: interval_point(100, 200, 0.5)
Out[ ]: 150.0
In [ ]: interval_point(100, 200, 0.2)
Out[ ]: 120.0
I came up with this:
def interval_point(a, b, x):
"""takes three numbers and interprets a and b as the start and end point
of an interval, and x as a fraction between 0 and 1 that determines how
far to go towards b, starting at a"""
if (a == b):
return a
if (x == 0):
return a
if (x > 0):
return((abs(a - b) + a) * x)
It worked for most of the tests that the automated test system looks for but it could't deal with a or b being a negative value.
Can someone suggest how I could make a function that does negative numbers as well as being able to handle if a is negative and b is positve.
Here was the report from the automated test system:
Test failure report
test_interval_point
def test_interval_point():
#if x=0, we expect to get value a back
assert s.interval_point(1.0, 2.0, 0.0) == 1.0
#if x=1, we expect to get value b back
assert s.interval_point(1.0, 2.0, 1.0) == 2.0
#test half-way, expect (a+b)/2
assert s.interval_point(1.0, 2.0, 0.5) == 1.5
#test trivial case of a=b
a, b = 1., 1.
x = 0.0
assert s.interval_point(a, b, x) == a
x = 1.0
assert s.interval_point(a, b, x) == a
x = 0.5
assert s.interval_point(a, b, x) == a
#test for negative numbers
assert s.interval_point(-2.0, -1.0, 0.5) == -1.5
#test for negative numbers
assert s.interval_point(-2.0, -1.0, 0.0) == -2.0
#test for negative numbers
assert s.interval_point(-2.0, -1.0, 1.0) == -1.0
#test for positive and negative limits
assert s.interval_point(-10, 10, 0.25) == -5.0

In addition to Goyo's comment, I would personally not check for edge-cases:
def interval_point(a, b, x):
return (b - a) * x + a
This should work for all values of a, b and x, including your special cases a == b and x == 0. If there is any performance gain by doing those checks, it will be negligable in most cases.
This version will also work if x is not in [0, 1], for example:
>>> interval_point(100, 200, 2)
300
>>> interval_point(100, 200, -1)
0
Which is probably acceptable. If not, your function should check that 0 <= x <= 1, because now your implementation of the function will return nothing if x < 0

Related

Is there a inner function that can calculate x=f-1 (y) when I know y=f(x)

for example, I define a function like that:
def trapezoid(x, a, b, c, d):
if x <= a:
return 0
if a < x <= b:
return (x - a)/(b - a)
if b < x <= c:
return 1
if c < x <= d:
return (d - x)/(d - c)
if d < x:
return 0
Now I can calculate the value of y according to input x, but if I know the value of y,how can I calculate x directly? Is there some way in numpy or other library?
for example:
print(trapezoid(12, 10, 30, 50, 90))
0.1
but if I know the result= 0.1, how to calculate the input x(12)? I know there may be a large number of x can get same y, but if I want to know the field of x?

Round up to certain number

Lets say I have a list of numbers: [0.13,0.53,2.83]
I want these numbers to round UP to the nearest x=0.5 (or any other value for x)
This list would then become, given x=0.5: [0.5,1,3].
I tried somethings with % but neither of what I tried seemed to work.
Any ideas?
Harry
EDIT: the other posts want to know the nearest value, so 1.6 would become 1.5, but in my case it should become 2
You need math.ceil:
import math
numbers = [0.13, 0.53, 2.83]
x = 0.5
def roundup(numbers, x):
return [math.ceil(number / x) * x for number in numbers]
roundup(numbers, x)
# returns [0.5, 1.0, 3.0]
If a function suits your need then the function bellow works for positive numbers. "x" is the number you want to round and thresh is the value (between 0 and 1) used to round up.
def rounding_function(x, thresh):
if x == int(x):
return x
else:
float_part = x-int(x)
if float_part<=thresh:
return int(x) + thresh
else:
return int(x) + 1
Which gives the following result:
l = [0, 0.13,0.53, 0.61, 2.83, 3]
print([rounding_function(x, 0.5) for x in l]) # [0, 0.5, 1, 1, 3, 3]
print([rounding_function(x, 0.6) for x in l]) # [0, 0.6, 0.6, 1, 3, 3]
Here's a general solution. (Don't forget to handle all the "weird input"; e.g. negative incr, negative x, etc.)
import math
def increment_ceil(x, incr=1):
"""
return the smallest float greater than or equal to x
that is divisible by incr
"""
if incr == 0:
return float(x)
else:
return float(math.ceil(x / incr) * incr)

calculate the mid points of a vector using Python

I started to learn python from scratch. I got some issues while doing the following problem.
I have the following vector ,x_vector = (0,1,2,3,4,5,6,7,8,9). Using this vector, I need to create this new vector x1 = (-0.5,0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5).
Basically the desired vector should have first element -0.5, mid points between each elements and the last element +0.5.
The code I tried so far as follows:
import numpy as np
x_vector=np.array([0,1,2,3,4,5,6,7,8,9])
x=len(x_vector)
mid=np.zeros(x+1)
for i in range (0,x):
if i==0 :
mid[i]= x_vector[i]-0.5
else :
mid[i]=(x_vector[i] + x_vector[i+1])/2
i +=1
Seems like this doesn't give the desired output. Can you one help me to figure out what can I do to get correct output?
Using itertools.pairwise:
from itertools import tee
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
res = []
res.append(min(x_vector)-0.5)
res.append(max(x_vector)+0.5)
res.extend([np.mean(z) for z in pairwise(x_vector)])
sorted(res)
Output:
[-0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]
Consider, what will happen for i = 0 and i = 1 in your loop:
mid[0] = x_vector[0] - 0.5 # = -0.5
mid[1] = (x_vector[1] + x_vector[2]) / 2 # (1 + 2) / 2 = 3 / 2 = 1 (or 1.5 if python3)
you mismatched indexes.
Try this:
for i in range (0,x):
if i == 0:
mid[i] = x_vector[i]-0.5
else :
mid[i] = (x_vector[i - 1] + x_vector[i]) / 2.0
Note, that i changed division to divide by 2.0 instead of 2 - this will make sure, that division result will be double (number with fraction) instead of integer (number without fraction, in python 2 division two integers will round to integer).
Also i += 1 is redundant, i variable in for loop will updated (overwriting your += 1 statement) every loop iteration.
It is not clear whether this is a homework, but given that you are using numpy I think it is fair game to use it as its whole potential, in this case you can just do:
import numpy as np
x_vector=np.array([0,1,2,3,4,5,6,7,8,9])
a = np.insert(x, 0, x[0] - 1)
b = np.append(x, x[-1] + 1)
mid = (a + b) / 2

Recursion function - Python

This is the problem:
Write a recursive function f that generates the sequence 0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875. The first two terms are 0 and 1, every other term is the average of the two previous.
>>> f(0)
0
>>> f(1)
1
>>> f(2)
0.5
>>> [(i,f(i)) for i in range(10)]
[(0, 0), (1, 1), (2, 0.5), (3, 0.75), (4, 0.625), (5, 0.6875), (6, 0.65625), (7, 0.671875), (8, 0.6640625), (9, 0.66796875)]
This is my code so far, I can't seem to figure it out. Any help/suggestions would be appreciated.
def f(n):
if n==0:
return 0
if n==1:
return 1
else:
return f(n-2)//f(n-1)
The recursive case is wrong:
return f(n-2)//f(n-1) # not the formula for the average of two numbers
The average of two numbers a and b is (a+b)/2. So you can define your function as:
def f(n):
if n==0:
return 0
if n==1:
return 1
else:
return (f(n-1)+f(n-2))/2
Or we can make it Python version-independent like:
def f(n):
if n==0:
return 0
if n==1:
return 1
else:
return 0.5*(f(n-1)+f(n-2))
You can then generate the sequence with list comprehension like:
>>> [f(i) for i in range(10)]
[0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
or by using a map:
>>> list(map(f,range(10)))
[0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
So you have U0 = 0, U1 = 1, and Un = (U(n-1) + U(n-2)) / 2 for n > 1.
You just have to literally translate this as a function:
def f(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return (f(n-1) + f(n-2)) / 2
Now for generating the sequence of the Ui from 0 to n:
def generate_sequence(n):
return [f(i) for i in range(n)]
This could (and really should) be optimized with memoization. Basically, you just have to store the previously computed results in a dictionary (while you could directly use a list instead in this case).
results = dict()
def memoized_f(n):
if n in results:
return results[n]
else:
results[n] = f(n)
return results[n]
This way, f(n) will be computed only once for each n.
As a bonus, when memoized_f(n) is called, the results dictionary holds the values of f(i) from 0 to at least n.
Recursion à la auxiliary function
You can define this using a simple auxiliary procedure and a couple state variables – the following f implementation evolves a linear iterative process
def f (n):
def aux (n, a, b):
if n == 0:
return a
else:
return aux (n - 1, b, 0.5 * (a + b))
return aux(n, 0, 1)
print([f(x) for x in range(10)])
# [0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
Going generic
Or you can genericize the entire process in what I'll call fibx
from functools import reduce
def fibx (op, seed, n):
[x,*xs] = seed
if n == 0:
return x
else:
return fibx(op, xs + [reduce(op, xs, x)], n - 1)
Now we could implement (eg) fib using fibx
from operator import add
def fib (n):
return fibx (add, [0,1], n)
print([fib(x) for x in range(10)])
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Or we can implement your f using fibx and a custom operator
def f (n):
return fibx (lambda a,b: 0.5 * (a + b), [0, 1], n)
print([f(x) for x in range(10)])
# [0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
Wasted computations
Some answers here are recursing with (eg) 0.5 * (f(n-1) + f(n-2)) which duplicates heaps of work. n values around 40 take astronomically longer (minutes compared to milliseconds) to compute than the methods I've described here.
Look at the tree recursion fib(5) in this example: see how fib(3) and fib(2) are repeated several times? This is owed to a naïve implementation of the fib program. In this particular case, we can easily avoid this duplicated work using the auxiliary looping function (as demonstrated in my answer) or using memoisation (described in another answer)
Tree recursion like this results in O(n2), whereas linear iterative recursion in my answer is O(n)
Generating a sequence for n
Another answer provided by #MadPhysicist generates a sequence for a single n input value – ie, f(9) will generate a list of the first 10 values. However, the implementation is simultaneously complex and naïve and wastes heaps of computations due to the same f(n-1), andf(n-2)` calls.
A tiny variation on our initial approach can generate the same sequence in a fraction of the time – f(40) using my code will take a fraction of a second whereas these bad tree recursion answers would take upwards of 2 minutes
(Changes in bold)
def f (n):
def aux (n, acc, a, b):
if n == 0:
return acc + [a]
else:
return aux (n - 1, acc + [a], b, 0.5 * (a + b))
return aux(n, [], 0, 1)
print(f(9))
# [0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
If you want a function that generates your sequence in a single call, without having to call the function for each element of the list, you can store the values you compute as you unwind the stack:
def f(n, _sequence=None):
if _sequence is None:
_sequence = [0] * (n + 1)
if n == 0 or n == 1:
val = n
else:
f(n - 1, _sequence)
f(n - 2, _sequence)
val = 0.5 * (_sequence[n - 1] + _sequence[n - 2])
_sequence[n] = val
return _sequence
This has the advantage of not requiring multiple recursions over the same values as you would end up doing with [f(n) for n in range(...)] if f returned a single value.
You can use a more global form of memoization as suggested by #RightLeg to record the knowledge between multiple calls.
Unlike the other solutions, this function will actually generate the complete sequence as it goes. E.g., your original example would be:
>>> f(9)
[0, 1, 0.5, 0.75, 0.625, 0.6875, 0.65625, 0.671875, 0.6640625, 0.66796875]
Another simple solution might look like this:
a=0.0
b=1.0
count = 0
def f(newavg, second, count):
avg = (second+newavg)/2
print avg
count=count+1
if count<8:
newavg = avg
f(second, avg, count)
f(a, b, count)
Granted this code just outputs to the monitor...if you want the output into a list just add the code in the recursion.
Also be careful to properly indent where required.

python fuction finding root( or zero) with minimum distance from real root epsilon

So its and exercises for python i am totally stuck! you have a random Function in [a,b] you already know that the a is negative and b is positive and it has only ONE root. The true root is : -0.94564927392359 and you have to make a
def that will find the root( or zero ) that will be closest to the true root with minimum difference eps.The eps is 1e-8 or 1e-6.Note that we don't know the true root, before was an example to understand what the number we are looking for is about. Also we are given the above :
import math
def fnc(x):
""" This the function in which root we are looking for """
global a, b, eps
if not hasattr(fnc, "counter"):
fnc.counter = 0
fnc.maxtimes = (int)(0.1+math.ceil(math.log((b-a)/eps, 2.0)+2))
if fnc.counter<fnc.maxtimes:
fnc.counter += 1
return x*x*x-x-0.1
else:
return 0.0 ##
WE have to start with this :
def root(f, a, b, eps):
(sorry for my English )
Just simple bisect:
from __future__ import division
import math
def func(x):
return x*x*x-x-0.1
def sign(n):
try:
return n/abs(n)
except ZeroDivisionError:
return 0
def root(f, a, b, eps=1e-6):
f_a = f(a)
if abs(f_a) < eps:
return a
f_b = f(b)
if abs(f_b) < eps:
return b
half = (b+a)/2
f_half = f(half)
if sign(f_half) != sign(f_a):
return root(f, a, half, eps)
else:
return root(f, half, b, eps)
print root(func, -1.5, -0.5, 1e-8) # -0.945649273694
See if the following heuristic of iteratively slicing intervals into 2 equals and then choosing the admissible half is suitable for you.
def root(fnc, a, b, eps = 1e-8, maxtimes = None):
if maxtimes == None: maxtimes = (int)(0.1+math.ceil(math.log((b-a)/eps, 2.0)+2))
for counter in xrange(maxtimes+1) : # a was assumed negative and b positive
if fnc(a) > -eps : return a, -fnc(a)
if fnc(b) < eps : return b, fnc(b)
new_bound = (a + b)/2.0
print a, b, new_bound
if fnc(new_bound) < 0 : a = new_bound
else : b = new_bound
return new_bound, min(-fnc(a),fnc(b))
and then
fnc = lambda x : x**3-x-0.1
result = root(fnc, 0, 2, 1e-6)
print "root = ", result[0], "error = ", result[1]

Categories

Resources