I have a sequence definition
xn+1 = f(xn , xn-1)
Where xn is x evaluated at time tn. Any value in the sequence is defined by some function of the previous two values (and the time step, but for now that's constant). I would like to generate the first N values in this sequence, given x0 & x1.
What's the most pythonic way to do this?
My current approach is just to loop. I create a numpy.ones array of the correct size, then loop through it by index. If index = 0 or 1 then I change the value from 1 to x0 / x1 respectively. For greater indecies I lookup the previous values in the array and apply the function.
But I feel like this doesn't seem to be making use of the numpy array methods, so I wonder if there's a better approach?
Code
In my code I have a createSequence function, which takes in a definition of xn+1 as well as boundary conditions and timestep, and outputs a sequence following those rules. NB, I'm very new to Python so any general advice would also be appreciated!
import numpy as np
def x_next(x_current,x_previous,dt):
"""Function to return the next value in the sequence
x_current and x_previous are the values at tn and tn-1 respectively
dt is the time step
"""
return (x_current - x_previous)/dt #as an example
def createSequence(x_next,x0,x1,start,stop,dt):
""" Function to create sequence based on x_next function, and boundary conditions"""
num = (stop-start)/dt
x_array = np.ones(int(num))
x_array[0] = x0
x_array[1] = x1
for index in range(len(x_array)):
if index == 0:
x_array[index] = x0
elif index == 1:
x_array[index] = x1
else:
x_current = x_array[index - 1]
x_previous = x_array[index - 2]
x_array[index] = x_next(x_current,x_previous,dt)
return x_array
print(createSequence(x_next=x_next,x0=0.1,x1=0.2,start=0,stop=20,dt=0.1))
I would recommend using a generator because
it allows you to generate sequences of arbitrary length without wasting memory
one might argue it is "pythonic".
In the following, I will use the Fibonacci sequence as an example because it takes a similar form to your problem.
def fibonacci(a=0, b=1, length=None):
# Generate a finite or infinite sequence
num = 0
while length is None or num < length:
# Evaluate the next Fibonacci number
c = a + b
yield c
# Advance to the next item in the sequence
a, b = c, a
num += 1
Note that a corresponds to your x_n, b corresponds to x_{n-1}, and c corresponds to x_{n+1}. And a simple example:
>>> list(fibonacci(length=10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
If you want to get the sequence into a numpy array
>>> np.fromiter(fibonacci(length=10), int)
array([ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55])
I think you want the initial collection of terms. However, if it should happen that you, or anyone reading this question, might want individual terms then the sympy library comes in handy. Everything here up to the horizontal line is from Solve a recurrence relation.
>>> from sympy import *
>>> var('y')
y
>>> var('n', integer=True)
n
>>> f = Function('f')
>>> f = y(n)-2*y(n-1)-5*y(n-2)
>>> r = rsolve(f, y(n), [1, 4])
Once you have r you can either evaluate it for various values of n within the sympy facilities ...
>>> N(r.subs(n,1))
4.00000000000000
>>> N(r.subs(n,2))
13.0000000000000
>>> N(r.subs(n,10))
265333.000000000
Or you could 'lift' the code in r and re-use it for your own routines.
>>> r
(1/2 + sqrt(6)/4)*(1 + sqrt(6))**n + (-sqrt(6) + 1)**n*(-sqrt(6)/4 + 1/2)
Related
I was asked to do the newton polynomial interpolation and I was able to write the main code.
https://en.wikipedia.org/wiki/Newton_polynomial
But there is still one small thing that I am not able to get around since a couple of days, after reading I found a way to do it using Sympy, but I am not allowed to use anything other than basic numpy.
Now my problem is that I trying to multiply something like this
p(x)=j(x-q)(x-w)(x-e)+k(x-w)(x-e)+l(x-e)+d
to get this p(x)=ax³+bx²+cx+d , so I amlooking for the polynomial coefficients a,b,c,d
for example:
p(x)=5-7(x+1)+9(x+1)(x)-7(x+1)(x)(x-1)=-7x³+9x²+9x-2
of course I am looking for the general case, not only for ploynomials from third degree.
Any tip would be much appreciated, I am really stuck at this since a couple of days.
and Sorry for the sloppy writing of notation, but it seems stackoverflow doesn't accept latex and I am not able to post a picture because I don't have rhe required reputation. (if there is other solutuions to post it properly please tell me and I'll just post it again)
Thanks in advance :)
First, I'll rewrite the equation as
c3(x-r3)(x-r2)(x-r1)+c2(x-r2)(x-r1)+c1(x-r1)+c0
Next, note that this is equivalent to:
((c3(x-r3)+c2)(x-r2)+c1)(x-r1)+c0
You can multiply it out if you want to check.
So in general, you can do:
poly = np.poly1d([c[n]])
for i in range(n,0,-1):
poly = poly*np.poly1d([1,-r[n]])+np.poly1d([n-1])
You can probably replace np.poly1d([c[n]]) with just c[n] and np.poly1d([c[n-1]]) with just c[n-1], if you're willing to trust the coercion to work properly
One way of doing it is to represent a polinomial as an array where a[0]..a[n] where a[i] is the constant that you multipliy (x^i). The function will be something like p(x) = a[0] + a[1]*x + a[2]* (x**2)....
Now to add two polinomials in this representation you just need to pad the shorter one with 0s and add the values at matching indices.
If you want to multiply a polinomial by k*(x**z) you need to multiply every value by k and insert z zeros in front( a[0:0] = [0.] * z).
Using these two operations you can resolve the equation and get the coefficients you want.
Multiplying two polynomials x(x-1) is the same as convolving their coefficients:
# x => [1, 0]
# (x-1) => [1, -1]
numpy.convolve([1, 0], [1, -1]) # [1, -1, 0] => x^2 - x + 0
This means you can solve the problem using
import numpy
def mult(a, b):
"""
Polynomial multiplication is simply a convolution
"""
return numpy.convolve(a, b)
def add(a, b):
"""
Addition is a bit complex as a and b may have different lengths.
Simply prepend zeros to the shorter one
"""
if len(a) < len(b):
a = numpy.insert(a, 0, [0] * (len(b) - len(a)))
if len(b) < len(a):
b = numpy.insert(b, 0, [0] * (len(a) - len(b)))
return a + b
# p(x)=5-7(x+1)+9(x+1)(x)-7(x+1)(x)(x-1)=-7x³+9x²+9x-2
add(
add(
numpy.array([5]),
mult([-7], [1, 1]),
),
add(
mult([9], mult([1, 1], [1, 0])),
mult([-7], mult([1, 1], mult([1, 0], [1, -1])))
)
)
yields
array([-7, 9, 9, -2]) # => -7x^3 + 9x^2 + 9x - 2
Using numpy, we have access to the poly1d object. With that, j(x-q)(x-w)(x-e)+k(x-w)(x-e)+l(x-e)+d is equivalent to:
In [ ]: j, q, w, e, k, w, l, d = range(1, 9)
...: poly1 = j*np.poly1d([-q, -w, -e], r=1)
...: poly2 = k*np.poly1d([-w, -e], r=0)
...: poly3 = l*np.poly1d([-e])
...: poly = poly1 + poly2 + poly3 + d
...: print(poly)
3 2
1 x + 12 x + 14 x + 8
I am trying to solve a primary equation with several variables. For example:11x+7y+3z=20. non-negative integer result only.
I use code below in python 3.5.1, but the result contains something like [...]. I wonder what is it?
The code I have is to test every variables from 0 to max [total value divided by corresponding variable]. Because the variables may be of a large number, I want to use recursion to solve it.
def equation (a,b,relist):
global total
if len(a)>1:
for i in range(b//a[0]+1):
corelist=relist.copy()
corelist+=[i]
testrest=equation(a[1:],b-a[0]*i,corelist)
if testrest:
total+=[testrest]
return total
else:
if b%a[0]==0:
relist+=[b//a[0]]
return relist
else:
return False
total=[]
re=equation([11,7,3],20,[])
print(re)
the result is
[[0, 2, 2], [...], [1, 0, 3], [...]]
change to a new one could get clean result, but I still need a global variable:
def equation (a,b,relist):
global total
if len(a)>1:
for i in range(b//a[0]+1):
corelist=relist.copy()
corelist+=[i]
equation(a[1:],b-a[0]*i,corelist)
return total
else:
if b%a[0]==0:
relist+=[b//a[0]]
total+=[relist]
return
else:
return
total=[]
print(equation([11,7,3],20,[]))
I see three layers of problems here.
1) There seems to be a misunderstanding about recursion.
2) There seems to be an underestimation of the complexity of the problem you are trying to solve (a modeling issue)
3) Your main question exposes some lacking skills in python itself.
I will address the questions in backward order given that your actual question is "the result contains something like [...]. I wonder what is it?"
"[]" in python designates a list.
For example:
var = [ 1, 2 ,3 ,4 ]
Creates a reference "var" to a list containing 4 integers of values 1, 2, 3 and 4 respectively.
var2 = [ "hello", ["foo", "bar"], "world" ]
var2 on the other hand is a reference to a composite list of 3 elements, a string, another list and a string. The 2nd element is a list of 2 strings.
So your results is a list of lists of integers (assuming the 2 lists with "..." are integers). If each sublists are of the same size, you could also think of it as a matrix. And the way the function is written, you could end up with a composite list of lists of integers, the value "False" (or the value "None" in the newest version)
Now to the modeling problem. The equation 11x + 7y + 3z = 20 is one equation with 3 unknowns. It is not clear at all to me what you want to acheive with this program, but unless you solve the equation by selecting 2 independent variables, you won't achieve much. It is not clear at all to me what is the relation between the program and the equation save for the list you provided as argument with the values 11, 7 and 3.
What I would do (assuming you are looking for triplets of values that solves the equation) is go for the equation: f(x,y) = (20/3) - (11/3)x - (7/3)y. Then the code I would rather write is:
def func_f(x, y):
return 20.0/3.0 - (11.0/3.0) * x - (7.0/3.0) * y
list_of_list_of_triplets = []
for (x, y) in zip(range(100),range(100)):
list_of_triplet = [x, y, func_f(x,y)]
list_of_list_of_triplets += [list_of_triplet] # or .append(list_of_triplet)
Be mindful that the number of solutions to this equation is infinite. You could think of it as a straight line in a rectangular prism if you bound the variables. If you wanted to represent the same line in an abstract number of dimensions, you could rewrite the above as:
def func_multi_f(nthc, const, coeffs, vars):
return const - sum([a*b/nth for a,b in zip(coeffs, vars)])
Where nthc is the coefficient of the Nth variable, const is an offset constant, coeffs is a list of coefficients and vars the values of the N-1 other variables. For example, we could re-write the func_f as:
def func_f(x,y):
return func_multi_f(3.0, 20.0, [11.0, 7.0], [x,y])
Now about recursion. A recursion is a formulation of a reducible input that can be called repetivitely as to achieve a final result. In pseudo code a recursive algorithm can be formulated as:
input = a reduced value or input items
if input has reached final state: return final value
operation = perform something on input and reduce it, combine with return value of this algorithm with reduced input.
For example, the fibonacci suite:
def fibonacci(val):
if val == 1:
return 1
return fibonacci(val - 1) + val
If you wanted to recusively add elements from a list:
def sum_recursive(list):
if len(list) == 1:
return list[0]
return sum_recursive(list[:-1]) + list[-1]
Hope it helps.
UPDATE
From comments and original question edits, it appears that we are rather looking for INTEGER solutions to the equation. Of non-negative values. That is quite different.
1) Step one find bounds: use the equation ax + by + cz <= 20 with a,b,c > 0 and x,y,z >= 0
2) Step two, simply do [(x, y, z) for x, y, z in zip(bounds_x, bounds_y, bounds_z) if x*11 + y*7 + z*3 - 20 == 0] and you will have a list of valid triplets.
in code:
def bounds(coeff, const):
return [val for val in range(const) if coeff * val <= const]
def combine_bounds(bounds_list):
# here you have to write your recusive function to build
# all possible combinations assuming N dimensions
def sols(coeffs, const):
bounds_lists = [bounds(a, const) for a in coeffs]
return [vals for vals in combine_bounds(bounds_lists) if sum([a*b for a,b in zip(coeff, vals)] - const == 0)
Here is a solution built from your second one, but without the global variable. Instead, each call passes back a list of solutions; the parent call appends each solution to the current element, making a new list to return.
def equation (a, b):
result = []
if len(a) > 1:
# For each valid value of the current coefficient,
# recur on the remainder of the list.
for i in range(b // a[0]+1):
soln = equation(a[1:], b-a[0]*i)
# prepend the current coefficient
# to each solution of the recursive call.
for item in soln:
result.append([i] + item)
else:
# Only one item left: is it a solution?
if b%a[0] == 0:
# Success: return a list of the one element
result = [[b // a[0]]]
else:
# Failure: return empty list
result = []
return result
print(equation([11, 7, 3], 20, []))
I want to split the value into number of spits provided. so for example if I have a value = 165340
and split = 5 then the list should become ['0-33068', '33069-66137', '66138-99204', '99205-132272', '132273-165340']...
so far I have just come up with something like this but this is not dynamic...
so thinking how can I build a list of strings like of numbers split with the difference val/split
for i in range(split):
if i==0:
lst.append('%s-%s' % (i, val/split))
elif i==1:
lst.append('%s-%s' % (val/split+i, val/split*2+1))
elif i == 2:
lst.append('%s-%s' % (val/split*i+2, val/split*3))
elif i == 3:
lst.append('%s-%s' % (val/split*i+1, val/split*4))
elif i == 4:
lst.append('%s-%s' % (val/split*i+1, val/split*5))
else:
pass
FINAL:
I made a bunch of attempts here, especially in using remainder = value % numsplits, then int(i * remainder // numsplits) to try and keep things close. Eventually, though, I had to give up and go back to floating point which seems to give the closest results. The usual floating point concerns apply.
def segment(value, numsplits):
return ["{}-{}".format(
int(round(1 + i * value/(numsplits*1.0),0)),
int(round(1 + i * value/(numsplits*1.0) +
value/(numsplits*1.0)-1, 0))) for
i in range(numsplits)]
>>> segment(165340, 5)
['1-33068', '33069-66136', '66137-99204', '99205-132272', '132273-165340']
>>> segment(7, 4)
['1-2', '3-4', '4-5', '6-7']
I don't see a huge issue with this one. I did start at 1 instead of 0, but that's not necessary (change both the int(round(1 + i * ... to int(round(i * ... to change that). Old results follow.
value = 165340
numsplits = 5
result = ["{}-{}".format(i + value//numsplits*i, i + value//numsplits*i + value//numsplits) for i in range(numsplits)]
Probably worth tossing in a function
def segment(value,numsplits):
return ["{}-{}".format(value*i//numsplits, 1 + value//numsplits*i + value//numsplits) for i in range(numsplits)]
The following will cut it off at your value
def segment(value, numsplits):
return ["{}-{}".format(max(0,i + value*i//numsplits), min(value,i + value*i//numsplits + value//numsplits)) for i in range(numsplits)]
To answer this question, it's important to know exactly how we should treat 0 - but it doesn't seem like you've asked yourself this question. The intervals in your example output are inconsistent; you're starting with 0 in the first interval and the first two intervals both have 33,069 elements (counting 0) in them, but you're also ending your last interval at 165340. If 0 and 165340 are both counted in the number of elements, then 165340 is not divisible into five even intervals.
Here are a few different solutions that might help you understand the problem.
Even intervals, counting from zero
Let's start with the assumption that you really do want both 0 and the "top" value counted as elements and displayed in the result. In other words, the value 11 would actually indicate the following 12-element range:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
And be evenly split into the following non-negative intervals:
['0-3', '4-7', '8-11']
If we're only concerned with evenly-divisible cases, we can use a fairly short function (NOTE: These solutions are valid for Python 3.x, or for Python 2.x with from __future__ import division):
>>> def evenintervals(value, n):
... binsize = (value + 1) // n
... intervals = ((x * binsize, (x + 1) * binsize - 1) for x in range(n))
... return ['{}-{}'.format(x, y) for x, y in intervals]
...
>>> evenintervals(11, 3)
['0-3', '4-7', '8-11']
>>> evenintervals(17, 2)
['0-8', '9-17']
However, this function deals with 165340 (and any other not-evenly-divisible case) by dropping some numbers off the end:
>>> evenintervals(165340, 5)
['0-33067', '33068-66135', '66136-99203', '99204-132271', '132272-165339']
From a purely mathematical perspective, this just doesn't work. However, we could fudge it a bit if for some reason you want to display 0, but not actually count it as an element of the first interval.
Even intervals, counting from one
Here's a function that doesn't count 0 as an element of the list, but does give you the option of displaying it, if you're just that zany:
>>> def evenintervals1(value, n, show_zero=False):
... binsize = value // n
... intervals = [[x * binsize + 1, (x + 1) * binsize] for x in range(n)]
... if show_zero:
... intervals[0][0] = 0
... return ['{}-{}'.format(x, y) for x, y in intervals]
...
>>> evenintervals1(20, 4)
['1-5', '6-10', '11-15', '16-20']
>>> evenintervals1(20, 5, show_zero=True)
['0-5', '6-10', '11-15', '16-20']
This version of the function might be the closest thing to what you asked for in your question, even though it doesn't show the exact values you gave in your example output:
>>> evenintervals1(165340, 5, show_zero=True)
['0-33068', '33069-66136', '66137-99204', '99205-132272', '132273-165340']
But we still have problems with inputs that aren't evenly divisible. What if we wanted a more general solution?
Uneven intervals
Let's think about how to deal with a wider range of inputs. We should be able to produce, from any positive integer n, anywhere from 1 to n non-overlapping ranges of positive integers. In other words, if our integer is 5, we want to be able to produce a list with as many as five ranges. But how should we distribute "extra" elements, in order to make the ranges as even as possible?
We probably don't want to distribute them randomly. We could just lengthen or shorten the last range in the list, but that has the potential to be very lop-sided:
# 40 split 7 times, adding remainder to last item
['1-5', '6-10', '11-15', '16-20', '21-25', '26-30', '31-40']
# 40 split 7 times, subtracting excess from last item
['1-6', '7-12', '13-18', '19-24', '25-30', '31-36', '37-40']
In the former case the last element is 100% larger than the others and in the latter case it's 33% smaller. If you're splitting a very large value into a much smaller number of intervals, this may not be as much of a problem.
More likely, we want a function that produces the most even set of ranges possible. I'm going to do this by spreading the remainder of the division out among the first elements of the list, with a little help from itertools:
>>> from itertools import zip_longest # izip_longest for Python 2.7
>>> def anyintervals(value, n):
... binsize, extras = value // n, value % n
... intervals = []
... lower = 0
... upper = 0
... for newbinsize in map(sum, zip_longest([binsize] * n, [1] * extras, fillvalue=0)):
... lower, upper = upper + 1, upper + newbinsize
... intervals.append((lower, upper))
... return ['{}-{}'.format(x, y) for x, y in intervals]
...
>>> anyintervals(11, 3)
['1-4', '5-8', '9-11']
>>> anyintervals(17, 2)
['1-9', 10-17']
Finally, with the example inputs given in the OP:
>>> anyintervals(165340, 5)
['1-33068', '33069-66136', '66137-99204', '99205-132272', '132273-165340']
If it were really important to show the first interval starting at zero, we could apply the same logic here that was used in evenintervals1 to modify the very first integer in intervals before returning, or write a similar function to this one that started counting at zero.
I did implement another version that distributes the "extras" among the last ranges rather than the first, and there are certainly many other implementations that you might be interested in fiddling around with, but those solutions are left as an exercise to the reader. ;)
One possibility using numpy:
from numpy import arange
v = 165340
s = 5
splits = arange(s + 1) * (v / s)
lst = ['%d-%d' % (splits[idx], splits[idx+1]) for idx in range(s)]
print '\n'.join(lst)
output:
0-33068
33068-66136
66136-99204
99204-132272
132272-165340
I have a numpy array of values like this:
a = np.array((1, 3, 4, 5, 10))
In this case the array has length 5. Now I want to know the difference between the lowest and highest value in the array, but only within a certain continuous part of the array, for example with length 3.
So in this case it would be the difference between 4 and 10, so 6. It would also be nice to have the index of the starting point of the continuous part (in the above example that would be 2). So something like this:
def f(a, lenght_of_part):
...
return (max_difference, starting index)
I know I could iterate over sliced parts of the array, but for my actual purpose I have ~150k arrays of length 1500, so that would take too long.
What would be an easy and quick way of doing this?
Thanks in advance!
This is a bit tricky to get done in a vectorised way in Numpy. One option is to use numpy.lib.stride_tricks.as_strided, which requires care, because it allows to access arbitrary memory. Here's an example for a window size of k = 3:
>>> k = 3
>>> shape = (len(a) - k + 1, k)
>>> b = numpy.lib.stride_tricks.as_strided(
a, shape=shape, strides=(a.itemsize, a.itemsize))
>>> moving_ptp = b.ptp(axis=1)
>>> start_index = moving_ptp.argmax()
>>> moving_ptp[start_index]
6
When appending longer statements to a list, I feel append becomes awkward to read. I would like a method that would work for dynamic list creation (i.e. don't need to initialize with zeros first, etc.), but I cannot seem to come up with another way of doing what I want.
Example:
import math
mylist = list()
phi = [1,2,3,4] # lets pretend this is of unknown/varying lengths
i, num, radius = 0, 4, 6
while i < num:
mylist.append(2*math.pi*radius*math.cos(phi[i]))
i = i + 1
Though append works just fine, I feel it is less clear than:
mylist[i] = 2*math.pi*radius*math.cos(phi[i])
But this does not work, as that element does not exist in the list yet, yielding:
IndexError: list assignment index out of range
I could just assign the resulting value to temporary variable, and append that, but that seems ugly and inefficient.
You don;t need an existing list and append to it later. Just use list comprehension
List comprehension,
is fast,
easy to comprehend,
and can easily be ported as a generator expression
>>> import math
>>> phi = [1,2,3,4]
>>> i, num, radius = 0, 4, 6
>>> circum = 2*math.pi*radius
>>> mylist = [circum * math.cos(p) for p in phi]
Reviewing your code, here are some generic suggestions
Do not compute a known constant in an iteration
while i < num:
mylist.append(2*math.pi*radius*math.cos(phi[i]))
i = i + 1
should be written as
circum = 2*math.pi
while i < num:
mylist.append(circum*math.cos(phi[i]))
i = i + 1
Instead of while use for-each construct
for p in phi:
mylist.append(circum*math.cos(p))
If an expression is not readable, break it into multiple statements, after all readability counts in Python.
In this particular case you could use a list comprehension:
mylist = [2*math.pi*radius*math.cos(phi[i]) for i in range(num)]
Or, if you're doing this sort of computations a lot, you could move away from using lists and use NumPy instead:
In [78]: import numpy as np
In [79]: phi = np.array([1, 2, 3, 4])
In [80]: radius = 6
In [81]: 2 * np.pi * radius * np.cos(phi)
Out[81]: array([ 20.36891706, -15.68836613, -37.32183785, -24.64178397])
I find this last version to be the most aesthetically pleasing of all. For longer phi it will also be more performant than using lists.
mylist += [2*math.pi*radius*math.cos(phi[i])]
you can use list concatenation, but append is twice as fast according to this:
import math
mylist = list()
phi = [1,2,3,4] # lets pretend this is of unknown/varying lengths
i, num, radius = 0, 4, 6
while i < num:
mylist += [(2*math.pi*radius*math.cos(phi[i]))]
i = i + 1