diff --git a/README.md b/README.md index a431d0b1cb853ddf30baa5776414626504791a14..dae1df22e109aaea41b09ac09db75d9cee013325 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,6 @@ Applying requires a callable(index: float, value: current value) -> value. Joining requires a callable(index: float, valueSelf, valueOther: values from self and other table) -> value. - ### DiscreteSeries To use a _DiscreteSeries_ you must give it a set of data to work with. These diff --git a/firanka/ranges.py b/firanka/ranges.py index 0d1256bbf9bea1eb49d403000868bc974f65dd65..b0554d43099c472a6a52bd85134f7dfca9fbe6ae 100644 --- a/firanka/ranges.py +++ b/firanka/ranges.py @@ -12,7 +12,7 @@ __all__ = [ ] -def _pre_range(fun): +def _pre_range(fun): # for making sure that first argument gets parsed as a Range @six.wraps(fun) def inner(self, arg, *args, **kwargs): if not isinstance(arg, Range): @@ -26,6 +26,7 @@ class Range(object): """ Range of real numbers. Immutable. """ + __slots__ = ('start', 'stop', 'left_inc', 'right_inc') def translate(self, x): if x == 0: @@ -61,8 +62,8 @@ class Range(object): else: args = self.__fromstr(rs) elif len(args) == 2: - args = args[0], args[1], not math.isinf(args[0]), not math.isinf( - args[1]) + a, b = args + args = a, b, not math.isinf(a), not math.isinf(b) return args @@ -142,12 +143,11 @@ class Range(object): assert self.start <= y.start - if (self.stop < y.start) or (y.stop < y.start): - return EMPTY_SET - - if self.stop == y.start and not (self.right_inc and y.left_inc): + if ((self.stop < y.start) or (y.stop < y.start)) or ( + self.stop == y.start and not (self.right_inc and y.left_inc)): return EMPTY_SET + # Set up range start if self.start == y.start: start = self.start left_inc = self.left_inc and y.left_inc @@ -155,6 +155,7 @@ class Range(object): start = y.start left_inc = y.left_inc + # Set up range end if self.stop == y.stop: stop = self.stop right_inc = self.right_inc and y.right_inc @@ -169,6 +170,7 @@ class Range(object): def __eq__(self, other): if self.is_empty() and other.is_empty(): return True + return self.start == other.start and self.stop == other.stop and self.left_inc == other.left_inc and self.right_inc == other.right_inc def __hash__(self): diff --git a/firanka/series/base.py b/firanka/series/base.py index efaa6cd4a35c58a8696669dd76fd2ca20c17e003..5be4ebe08b758bf818d011bc5645c0b90e2bd568 100644 --- a/firanka/series/base.py +++ b/firanka/series/base.py @@ -68,7 +68,7 @@ class Series(object): """ assert _has_arguments(fun, 2), 'Callable to apply needs 2 arguments' - return AlteredSeries(self, applyfun=fun) + return AlteredSeries(self, fun=fun) def discretize(self, points, domain=None): """ @@ -191,7 +191,19 @@ class DiscreteSeries(Series): return DiscreteSeries(c, new_domain) + def join(self, series, fun): + if isinstance(series, DiscreteSeries): + return self.join_discrete(series, fun) # same effect + else: + super(DiscreteSeries, self).join(series, fun) + def join_discrete(self, series, fun): + """ + Very much like join, but it will evaluate only existing discrete points. + :param series: + :param fun: + :return: + """ assert _has_arguments(fun, 3), 'fun must have at least 3 arguments!' new_domain = self.domain.intersection(series.domain) @@ -199,21 +211,19 @@ class DiscreteSeries(Series): if isinstance(series, DiscreteSeries): return self._join_discrete_other_discrete(series, fun) + def get_both_for_t(t): + return fun(t, self._get_for(t), series._get_for(t)) + + c = [] if new_domain.start > self.data[0][0]: - c = [(new_domain.start, fun(new_domain.start, - self._get_for(new_domain.start), - series._get_for(new_domain.start)))] - else: - c = [] + c.append((new_domain.start, get_both_for_t(new_domain.start))) for k, v in ((k, v) for k, v in self.data if new_domain.start <= k <= new_domain.stop): _appendif(c, k, fun(k, v, series._get_for(k))) if c[-1][0] != new_domain.stop: - c.append((new_domain.stop, fun(new_domain.stop, - self._get_for(new_domain.stop), - series._get_for(new_domain.stop)))) + c.append((new_domain.stop, get_both_for_t(new_domain.stop))) return DiscreteSeries(c, new_domain) @@ -223,16 +233,16 @@ class AlteredSeries(Series): Internal use - for applyings, translations and slicing """ - def __init__(self, series, domain=None, applyfun=lambda k, v: v, x=0, *args, **kwargs): + def __init__(self, series, domain=None, fun=lambda k, v: v, x=0, *args, **kwargs): """ :param series: original series :param domain: new domain to use [if sliced] - :param applyfun: (index, v) -> newV [if applied] + :param fun: (index, v) -> newV [if applied] :param x: translation vector [if translated] """ domain = domain or series.domain super(AlteredSeries, self).__init__(domain.translate(x), *args, **kwargs) - self.fun = applyfun + self.fun = fun self.series = series self.x = x