# Implementation of module {rootray}. # Last edited on 2021-02-18 22:24:13 by jstolfi import rn from math import hypot, inf import sys def min_sep(t1,t2): e1 = 1.0e-8*t1 e2 = 1.0e-8*t2 eps = 1.0e-100 + hypot(e1,e2) assert eps != +inf, "not applicable to infinities" return eps def vacuum(): return (+1,[]) def plenum(): return (-1,[]) def complement(f): assert (type(f) is tuple or type(f) is list) and len(f) == 2 s, T = f return (-s, T) def union(f1, f2): # sys.stderr.write("\n") # sys.stderr.write("--- enter union ---\n") # sys.stderr.write("f1 = %s f2 = %s\n" % (str(f1),str(f2))) assert (type(f1) is tuple or type(f1) is list) and len(f1) == 2 s1, T1 = f1 assert (type(f2) is tuple or type(f2) is list) and len(f2) == 2 s2, T2 = f2 # Merge root times removing buried ones: n1 = len(T1); k1 = 0; t1 = T1[0] if n1 >0 else +inf n2 = len(T2); k2 = 0; t2 = T2[0] if n2 >0 else +inf s = -1 if s1 < 0 or s2 < 0 else +1 T = [] tant = -inf scur = s while t1 < +inf or t2 < +inf: # At this point we have created in {T} the root-ray up to time {tcur=tant+eps} # and the status of {r(tcur)} relative to the union is given by {scur}. # Also the status of {r1(tcur)} and {r2(tcur)} is {s1} and {s2}, respectively. # The next root times of {f1} and {f2} after {tant} are {t1} and {t2} # wich are {T1[k1]} and {T2[k2]} if those elements exist. # sys.stderr.write("\n") # sys.stderr.write("tant = %12.8f s1 = %+2d s2 = %+2d scur = %+2d\n" %(tant,s1,s2,scur)) assert scur < 0 or s1 > 0 or s2 > 0 # Identify the next event: tnext = min(t1, t2) assert tnext > tant # Identify the status of the two root-rays and of the union after the next event: if tnext == t1: s1 = -s1; if tnext == t2: s2 = -s2; snext = -1 if s1 < 0 or s2 < 0 else +1 # sys.stderr.write("tnext = %12.8f s1 = %+2d s2 = %+2d snext = %12.8f \n" % (tnext,s1,s2,snext)) # See if union changed: if snext != scur: # Append {tnext} and flip the status: scur = snext T.append(tnext) # In any case, advance to {tnext+eps} tant = tnext # Advance the two operands: if tnext < +inf: if t1 == tnext: assert k1 < n1; k1 = k1 + 1; t1 = T1[k1] if k1 < n1 else +inf if t2 == tnext: assert k2 < n2; k2 = k2 + 1; t2 = T2[k2] if k2 < n2 else +inf # sys.stderr.write("union: s = %d T = %s\n" % (s, T)) return (s, remove_near_dups(T)) def remove_near_dups(T): # Returns a copy of {T} removing all pairs of # consecutive elements that are not well-separated. # sys.stderr.write("remove_near_dups: T = %s\n" % str(T)) n = len(T) Tclean = [] k = 0 # Next element of {T} to consider tant = -inf # Last element added to {Tclean} while k < n-1: # At this point {T[k]} and {T[k+1]} exist, and all elements of {T} # before {T[k]} have been added to {Tclean}, and are well separated # from {T[k]}. ta = T[k]; tb = T[k+1] # sys.stderr.write("remove_near_dups: k= %d ta = %21.15e tb = %21.15e\n" % (k, ta, tb)) assert -inf < ta and ta < tb and tb < +inf if tb - ta < min_sep(ta, tb): # Eliminate {T[k]} and {T[k+1]}: k = k + 2 else: # Safe to add {T[k]}: if tant != -inf: assert ta - tant > min_sep(tant, ta) Tclean.append(ta) tant = ta k = k + 1 # Add the last unpaired element if any: if k < n: ta = T[k] if tant != -inf: assert ta - tant > min_sep(tant, ta) Tclean.append(ta); k = k + 1 assert k == n return Tclean def intersection(f1, f2): # sys.stderr.write("\n") # sys.stderr.write("--- enter intersection ---\n") # sys.stderr.write("f1 = %s f2 = %s\n" % (str(f1),str(f2))) return complement(union(complement(f1), complement(f2))) def difference(f1, f2): return complement(union(complement(f1), f2)) def clip_time(f, tmin, tmax): assert (type(f) is tuple or type(f) is list) and len(f) == 2 assert tmin < tmax s, T = f Tnew = [] tant = -inf for t in T: assert tant < t and t < +inf if t >= tmax: break elif t > tmin: Tnew.append(t) else: s = -s tant = t return (s, Tnew) def validate(f): assert (type(f) is tuple or type(f) is list) and len(f) == 2 s,T = f assert type(s) is int and (s == -1 or s == +1) assert type(T) is list or type(T) is tuple tant = -inf for t in T: assert type(t) is int or type(t) is float assert t > tant and t < +inf if tant != -inf: assert t - tant > min_sep(tant, t)