#!/usr/bin/env python
# -*- coding: cp1252 -*-

# Author: Jakob Fastenbauer (hu8 @muuuuuh@@_ aitchyou8.net)
# Date: 18.10.2007
# Version: 0.1
# License: Use at your own risks etc... (do whatever you want, 
# but maybe mention my name or my homepage if you want;))
# Homepage: http://www.aitchyou8.net
# Script: http://www.aitchyou8.net/misc/suite.py
from math import *

class Suite:
    """Eine simple Klasse um Folgen zu berechnen.

    Es koennen sowohl Folgen die funktional als auch welche die rekursiv
    definiert sind berechnet werden.

    Die expression muss immer n beinhalten, sonst NUR Zahlen, *, +, - etc...
    first ist der erste Term bei einer Folge die rekursiv definiert ist.
    recursive ist False wenn die Folge funktional definiert ist, sonst True.

    Es ist moeglich alle Funktionen die in math.* sind zu benutzen.

    ACHTUNG: Es wird eval() verwendet!!!
    ACHTUNG: Folgen die rekursiv definiert sind...kann man zwar beliebig hohe Terme berechnen
    man muss aber aufpassen nicht ueber das recursion limit von python zu kommen.
    Da die Ergebnisse gecachet werden, kann man das uebergehen indem man
    die Berechnung von u(100) folgendermassen durchfuehrt:
    u(100);u(200);u(300);u(400);u(500)...
    """
    def __init__(self, expression, first={0:0}, recursive=False):
        self.expression = expression # A string like n^2
        if recursive:
            self.value_dict = first
            self.first = first.keys()[0]
        else:
            self.value_dict = {}
        self.recursive = recursive

    def calc(self, n):
        """Berechnet einen Term n"""
        if self.recursive:
            if n in self.value_dict:
                return self.value_dict[n]
            if n == self.first:
                return self.value_dict[n]
            else:
                previous = self.calc(n-1)
                res = eval(self.expression.replace("n", str(previous)))
                self.value_dict[n] = res
                return res
        else:
            if not n in self.value_dict:
                res = eval(self.expression.replace("n", str(n)))
                self.value_dict[n] = res
                return res
            else:
                return self.value_dict[n]

    def __call__(self, n):
        return self.calc(n)

def test():
    ms = Suite("5*n")
    print ms(0)
    print ms(5)
    print ms.calc(10)
    ms = Suite("2*n", {1:1}, True)
    print ms(1)
    print ms(2)
    print ms.calc(10)

if __name__ == '__main__':
    test()

