"""One-dimensional random isolation trees; not sklearn or standard IF score."""
from fractions import Fraction as F
from random import Random
import math,json
def tree(values,seed):
    if not values or not all(type(v) in (int,float) and math.isfinite(v) for v in values):raise ValueError('finite nonempty values')
    rng=Random(seed)
    def split(ids,depth):
        lo=min(values[i] for i in ids);hi=max(values[i] for i in ids)
        if lo==hi:return {'ids':ids,'depth':depth,'leaf':True}
        ratio=F(rng.randrange(1,1000),1000);cut=F(lo)+(F(hi)-F(lo))*ratio
        left=[i for i in ids if values[i]<cut];right=[i for i in ids if values[i]>=cut]
        assert left and right
        return {'feature':0,'cut':str(cut),'depth':depth,'left':split(left,depth+1),'right':split(right,depth+1)}
    return split(list(range(len(values))),0)
def leaf_paths(node):
    if node.get('leaf'):return {i:node['depth'] for i in node['ids']}
    return {**leaf_paths(node['left']),**leaf_paths(node['right'])}
def run():
    values=[0,1,2,3,10];seeds=[7,11,19];trees=[tree(values,s) for s in seeds];paths=[leaf_paths(t) for t in trees]
    means=[sum((F(p[i]) for p in paths),F(0))/len(paths) for i in range(len(values))]
    assert tree([1,1],7)=={'ids':[0,1],'depth':0,'leaf':True}
    assert tree([4],7)['depth']==0 and tree(values,7)==trees[0]
    assert all(set(p)==set(range(5)) for p in paths)
    return {'values':values,'seeds':seeds,'trees':trees,'depths_by_row':[[p[i] for p in paths] for i in range(5)],'mean_leaf_depths':[str(v) for v in means],'standard_IF_score_computed':False,'sklearn_run':False,'training_data_fictional':True}
if __name__=='__main__':print(json.dumps(run(),indent=2))
