#!/usr/bin/env python3
"""Original standard-library implementation of Lab 05's analytical residual toy."""
import json, math, platform
from numbers import Real

def vector(x):
    if len(x)!=3 or any(type(v) is bool or not isinstance(v,Real) or not math.isfinite(v) for v in x):
        raise ValueError('Use three finite real coordinates')
    return list(x)

def add(x,y):
    vector(x);vector(y)
    return [a+b for a,b in zip(x,y)]

def first(x):
    x=vector(x);return [-x[0],2,0]

def second(x):
    x=vector(x);return [x[1],-x[1],2*x[0]]

def trace(x,suppress=None,parallel=False):
    x=vector(x)
    if suppress not in (None,'first','second'):raise ValueError('Unknown branch')
    a=[0,0,0] if suppress=='first' else first(x);y=add(x,a)
    b=[0,0,0] if suppress=='second' else second(x if parallel else y);z=add(y,b)
    vectors={'input':x,'first_update':a,'intermediate':y,'second_update':b,'final':z}
    return {'vectors':vectors,'norms':{k:math.sqrt(sum(v*v for v in row)) for k,row in vectors.items()},
            'total_change':[v-u for u,v in zip(x,z)],'readout':z[2]}

if __name__=='__main__':
    print(json.dumps({'python':platform.python_version(),'baseline':trace([1,2,-1]),
                     'suppress_first':trace([1,2,-1],'first'),'suppress_second':trace([1,2,-1],'second'),
                     'parallel':trace([1,2,-1],parallel=True),'second_position':trace([-2,0,3])},indent=2))
