I have two sets of numbers
xl=linspace(0.,1,1000)
xu=linspace(0.,1,1000)+0.5
which should form pairwise intervals over which I want to run a polynomial function.
I want to store the resulting values for each interval, as lists within a list.
The only way I can think of is the following:
-Variables
xl=linspace(0.,1,1000)
xu=linspace(0.,1,1000)+0.5
M=[]-the list where the intervals are to be stored
Values=[] # The list where the output of the polynomial function will be stored.
class Interval:
def __init__(self,left,right):
self.left=left
self.right=right
def __repr__(self):
return'[{},{}]'.format(self.left,self.right)
def BuildIntervalFromLists(x,y): (builds the list of intervals)
for i, j in zip(x, y):
M.append(Interval(i,j))
return M
def Polynomial(t): (The function)
3*t**3-2*t**2-5*t-1
def PolynomialFunction(x): (Function to run over all intervals)
for k in x: # The intervals in sequence
for l in k: # The numbers in each interval in sequence
Values.append([Polynomial(l)])
return(Values)
BuildIntervalFromLists(xl,xu)
PolynomialFunction(M)
This, however, gives the error message that I can't run an iteration over an interval.
Is there any way of getting around this problem?
If not, is there a better approach?
There is a special method in python which is called getitem to reach an item inside of an object. You can simply define it as follows:
def __getitem__(self, position):
return self.my_array[position]
As you can see I also define my_array variable inside the class. So the new class implementation will be like this:
class Interval:
def __init__(self,left,right):
self.left=left
self.right=right
self.my_array = [left,right]
def __repr__(self):
return'[{},{}]'.format(self.left,self.right)
def __getitem__(self, position):
return self.my_array[position]
Now, you can see the variables inside of your class thanks to repr and you can iterate them by using getitem
The overall code will be like this:
import numpy as np
xl=np.linspace(0.,1,1000)
xu=np.linspace(0.,1,1000)+0.5
M=[]
Values=[] # The list where the output of the polynomial function will be stored.
class Interval:
def __init__(self,left,right):
self.left=left
self.right=right
self.my_array = [left,right]
def __repr__(self):
return'[{},{}]'.format(self.left,self.right)
def __getitem__(self, position):
return self.my_array[position]
def BuildIntervalFromLists(x,y):
for i, j in zip(x, y):
M.append(Interval(i,j))
return M
def Polynomial(t):
return 3*t**3-2*t**2-5*t-1
def PolynomialFunction(x):
for k in x: # The intervals in sequence
for l in k: # The numbers in each interval in sequence
Values.append([Polynomial(l)])
return(Values)
BuildIntervalFromLists(xl,xu)
PolynomialFunction(M)
I hope it will solve your problem. Best
Related
I have two classes, for the example I will call them "Point" and "Vector" (like in math). I want one of the classes be called by the other to "convert" for example a point into the according vector ((1,2,1) -> (1,2,1)T).
argsintfloat = lambda l: all(isinstance(i, (int,float,complex)) for i in l)
class Point:
def __init__(self, *args):
if not argsintfloat(args):
raise ValueError("non-numeral values are not supported")
self.coordinates = args
def Vector(self):
return Vector(*self.coordinates)
class Vector:
def __init__(self, *args):
if not argsintfloat(args):
raise ValueError("non-numeral values are not supported")
self.components = args
def Point(self):
return Point(*self.components)
Now when for example calling the following:
point1 = Point(1,2,3,4)
vector1 = Vector(point1)
I just arrive at the ValueError
ValueError: non-numeral values are not supported
as expected when the values given aren't int, float or complex. I understand why this problem is occuring; the class Vector is called instead of the function Vector in the class Point and since a class object isn't an int, float or complex... Normally I'd just call that function with
point1.Point()
but I don't want to solve this problem with that. I want to make this as visually easy as possible without further specifying the args types conversion in init(). Anyone have an idea on how to achieve that?
While you could examine the arguments to Vector.__init__ to see if you got multiple numbers or a single Point, it would be better to use a class method to decompose the Point into values that can be passed to __init__.
class Vector:
def __init__(self, *args):
if not argsintfloat(args):
raise ValueError("non-numeral values are not supported")
self.components = args
def to_point(self):
return Point(*self.components)
#classmethod
def from_point(cls, p: Point):
return cls(*p.components)
point1 = Point(1,2,3,4)
vector1 = Vector.from_point(point1)
The same argument applies to your Point class:
class Point:
def __init__(self, *args):
if not argsintfloat(args):
raise ValueError("non-numeral values are not supported")
self.coordinates = args
def to_vector(self):
return Vector(*self.coordinates)
#classmethod
def from_vector(cls, v: Vector):
return cls(*v.components)
In mathematical terms, Vector and Point are isomorphic, meaning you can losslessly convert from a value of one type to the other. Specifically, if you have a Point p, then p == Point.from_vector(p.to_vector()), and if you have a Vector v, then v == Vector.from_point(v.to_point()).
The problem in the code is that Vector.numerical_vector is a list of copies of floats, but I need it to be list of references, so when Vector.vector[n].value is changed, Vector.numerical_vector[n] is changed to the same value as well.
Thanks for help in advance!
class Var:
def __init__(self, val):
self.value = float(val)
def __float__(self):
return self.value
class Vector:
def __init__(self, vector):
self.vector = vector
self.numerical_vector = [float(x) for x in vector]
vars = [Var(i) for i in range(5)]
vector = Vector(vars)
There's no way to do that in python. What you could do is make numerical_vector an object that, when accessed, returns the float value of the corresponding vector item. Eg
class VectorWrapper:
def __init__(self, vector):
self.vector = vector
def __getitem__(self, i):
return float(self.vector[i])
and set self.numerical_vector = VectorWrapper(self.vector)
If you have to return a float representation when self.numerical_vector[i] is referenced,
You might want to employ a property for that.
class Vector:
def __init__(self, vector):
self.vector = vector
#property
def numerical_vector(self):
return [x.value for x in self.vector]
Now vector.numerical_vector will always be synchronized. A drawback of this method is that it is recomputed each time you access it, some it may not be adapted to your specific application.
If performance is an issue, you could add __getitem__ and __setitem__ methods to Vector as follows:
class Vector:
def __init__(self, vector):
self.vector = vector
self.numerical_vector = [float(x) for x in vector]
def __getitem__(self, i):
return self.vector[i]
def __setitem__(self, i, val):
self.vector[i] = val
self.numerical_vector[i] = float(val)
In that case, if you set vector_instance[i], then vector_instance.numerical_vector[i] will be also modified. But if you want to modify vector_instance.vector[i] directly, then synchronicity will be broken.
Depending on the use case, you can use either of the two approaches. Both have limitations but I don't think much more can be done.
I'd like to return either one or two variables for a function in python(3.x). Ideally, that would depend on amount of returned variables requested by user on function call. For example, the max() function returns by default the max value and can return the argmax. In python, that would look something like:
maximum = max(array)
maximum, index = max(array)
Im currently solving this with an extra argument return_arg:
import numpy as np
def my_max(array, return_arg=False):
maximum = np.max(array)
if return_arg:
index = np.argmax(array)
return maximum, index
else:
return maximum
This way, the first block of code would look like this:
maximum = my_max(array)
maximum, index = my_max(array, return_arg=True)
Is there a way to avoid the extra argument? Maybe testing for how many vaules the user is expecting? I know you can return a tuple and unpack it when calling it (that's what I'm doing).
Asume the actual function I'm doing this in is one where this behaviour makes sense.
You can instead return an instance of a subclass of int (or float, depending on the data type you want to process) that has an additional index attribute and would return an iterator of two items when used in a sequence context:
class int_with_index(int):
def __new__(cls, value, index):
return super(int_with_index, cls).__new__(cls, value)
def __init__(self, value, index):
super().__init__()
self.index = index
def __iter__(self):
return iter((self, self.index))
def my_max(array, return_arg=False):
maximum = np.max(array)
index = np.argmax(array)
return int_with_index(maximum, index)
so that:
maximum = my_max(array)
maximum, index = my_max(array)
would both work as intended.
The answer is no, in Python a function has no context of the caller and can't know how many values the caller expects in return.
Instead in Python you would rather have different functions, a flag in the function signature (like you did) or you would return an object with multiple fields of which the consumer can take whatever it needs.
No, there is no way of doing this. my_max(array) will be called and return before assigning a value to maximum. If more than one value is returned by the function then it will try unpacking the values and assigning them accordingly.
Most people tackle this problem by doing this:
maximum, _ = my_max(array)
maximum, index = my_max(array)
or
maximum = my_max(array)[0]
maximum, index = my_max(array)
If you need a solution that works for any data type such as np.ndarray, you can use a decorator that uses ast.NodeTransformer to modify any assignment statement that assigns a call to a given target function name (e.g. my_max) to a single variable name, to the same statement but assigns to a tuple of the same variable name plus a _ variable (which by convention stores a discarded value), so that a statement such as maximum = my_max(array) is automatically transformed into maximum, _ = my_max(array):
import ast
import inspect
from textwrap import dedent
class ForceUnpack(ast.NodeTransformer):
def __init__(self, target_name):
self.target = ast.dump(ast.parse(target_name, mode='eval').body)
def visit_Assign(self, node):
if isinstance(node.value, ast.Call) and ast.dump(node.value.func) == self.target and isinstance(node.targets[0], ast.Name):
node.targets[0] = ast.Tuple(elts=[node.targets[0], ast.Name(id='_', ctx=ast.Store())], ctx=ast.Store())
return node
# remove force_unpack from the decorator list to avoid re-decorating during exec
def visit_FunctionDef(self, node):
node.decorator_list = [
decorator for decorator in node.decorator_list
if not isinstance(decorator, ast.Call) or decorator.func.id != "force_unpack"
]
self.generic_visit(node)
return node
def force_unpack(target_name):
def decorator(func):
tree = ForceUnpack(target_name).visit(ast.parse(dedent(inspect.getsource(func))))
ast.fix_missing_locations(tree)
scope = {}
exec(compile(tree, inspect.getfile(func), "exec"), func.__globals__, scope)
return scope[func.__name__]
return decorator
so that you can define your my_max function to always return a tuple:
def my_max(array, return_arg=False):
maximum = np.max(array)
index = np.argmax(array)
return maximum, index
while applying the force_unpack decorator to any function that calls my_max so that the assignment statements within can unpack the returning values of my_max even if they're assigned to a single variable:
#force_unpack('my_max')
def foo():
maximum = my_max(array)
maximum, index = my_max(array)
def find_closest(data, target, key = lambda x:f(x))
This is my function definition where data is set of values, and I want to find the value that evaluates the closest to target in as few evaluations as possible, i.e. abs(target-f(x)) is minimum. f(x) is monotonic.
I've heard that binary search can do this in O(log(n)) time, is there a library implementation in python? Are there more efficient search algorithms?
EDIT: I'm looking to minimize complexity in terms of evaluating f(x) because that's the expensive part. I want to find the x in data that when evaluated with f(x), comes closest to the target. data is in the domain of f, target is in the range of f. Yes, data can be sorted quickly.
You can use the utilities in the bisect module. You will have to evaluate x on data though, i.e. list(f(x) for x in data) to get a monotonic / sorted list to bisect.
I am not aware of a binary search in the standard library that works directly on f and data.
If the data presented is already sorted and the function is strctly monotonic,
apply the function f on the data and then perform a binary search using bisect.bisect
import bisect
def find_closest(data, target, key = f):
data = map(f, data)
if f(0) > f(1):
data = [-e for e in data]
try:
return data[bisect.bisect_left(data, target)]
except IndexError:
return data[-1]
Use bisect_left() method to find lower bound.
Bisect_left accepts a random-access list of elements, to avoid calculating all of them you can use lazy collection of calculated function values with __len__ and __getitem__ methods defined.
Carefully check return value for border conditions.
Your heavy calculation will be called O(log(N) + 1) = O(log(N)) times.
from bisect import bisect_left
from collections import defaultdict
class Cache(defaultdict):
def __init__(self, method):
self.method = method
def __missing__(self, key):
return self.method(key)
class MappedList(object):
def __init__(self, method, input):
self.method = method
self.input = input
self.cache = Cache(method)
def __len__(self):
return len(self.input)
def __getitem__(self, i):
return self.cache[input[i]]
def find_closest(data, target, key = lambda x:x):
s = sorted(data)
evaluated = MappedList(key, s)
index = bisect_left(evaluated, target)
if index == 0:
return data[0]
if index == len(data):
return data[index-1]
if target - evaluated[index-1] <= evaluated[index] - target:
return data[index-1]
else:
return data[index]
I just learned yesterday from this site that I can:
class Seq(object):
def __init__(self, seq):
self.seq = seq
def __repr__(self):
return repr(self.seq)
def __str__(self):
return str(self.seq)
def all(self):
return Seq(self.seq[:])
def head(self, count):
return Seq(self.seq[:count])
def tail(self, count):
return Seq(self.seq[-count:])
def odd(self):
return Seq(self.seq[1::2])
def even(self):
return Seq(self.seq[::2])
def reverse(self):
return Seq(self.seq[::-1])
>>> s = Seq(range(0, 100))
>>> print s.head(10).odd().even().reverse()
[9, 5, 1]
I want to enumerate possible combination of those sequence method chains inside of class Seq, may sort of:
itertools.product([s.head,s.odd,s.even,s.reverse], repeat=4)
# may not just limited those 4 functions
how to use the itertools.product() to
1). generate invoke-able function chains list? just like this:
foo = s.head().odd().even().reverse()
2). generate eval()able chain strings then I can store in ascii file or eval() later or for logging purpose?
the head(), tail() may accept parameter, and even(), odd() is not need to, for example,
the paremeter of head() and tail() may from lists:
head_lmt = [10,20,30]
tail_lmt = [30,40,50]
foo = s.head().odd().tail().reverse()
^------------------------------------head_lmt 10 or 20 or 30
^-----------------------tail_lmt 30 or 40 or 50
If my Q1 is possible, how I can fill those parameter into the invoke-able list and the eval()-able string, a.k.a generate more specific invoke-able list and the eval()-able string?
Thanks!
Note that something like "s.head()" means a method which is "bound" to that specific instance of Seq, that is, "s." Something like "Seq.head()" means a method which is unbound, so one can still pass in different instances of Seq.
From there it simply requires basic functional composition and string concatenation.
def chain_method(from_method, to_method):
def inner(arg):
return to_method(from_method(arg))
return inner
possible_funcs = []
log_strings = []
for possible_combo in itertools.product([Seq.head,Seq.odd,Seq.even,Seq.reverse], repeat=4):
meta_method = possible_combo[0]
for method in possible_combo[1:]:
meta_method = chain_method(meta_method, method)
log_string = []
for method in possible_combo:
log_string.extend(['.', method.__name__, '()'])
possible_funcs.append(meta_method)
log_strings.append("".join(log_string))
I'm not sure what you mean by the examples for the additional parameters, though. How do you intend to combine the different parameter values with the different combinations of functions?