# Tools for generic geometric transformations in arbitrary spaces. # Last edited on 2021-02-08 20:29:59 by jstolfi import trafo_IMP; from trafo_IMP import Trafo_IMP def module_doc(): # This module is about the representation of arbitrary # transformations in some unspecified geometric and topological /space/ {\RX}, such as # {n}-dimensional Cartesian or projective space, whose elements will be # called /points/. # # A /transformation/, or /trafo/ for short, is continuous bijection (a # homeomorphism) of the space to itself. Applying a trafo {T} to a set # of points {X} produces another set {Y = T(X) = {T(x) : x \in X}} Note # that if {X} is empty or the whole space, {T(X)} will be {X} for any # trafo {T}. plenum, {T(F)} is always {F}. Note also that geometric # transformations commute with set complement and distribute over set # union and intersection. class Trafo(Trafo_IMP): # An object {T} of this class represents a transformation of the space # {\RX}. The nature of {\RX} and of the transformation is defined only # by subclasses. # # To create elements of this class, use "Trafo(nn)" where {nn} is {None} # or a string that is used in printouts and debigging as the trafo's name. # The only method is {T.get_name()} that returns that string. # # For the procedures of this module, a trafo may be either a {Trafo} # object, or a tuple {(i, T1,T2,..Tn)} where {i} is {+1} or {-1} # and {T1,T2,...,Tn} are trafos. If {i} is {+1}, the tuple represents the # compostion of those trafos, applied in that order; if {i} is {-1}, it # represents the inverse of that, namely the inverses of {Tn,...,T2,T1} # applied in this order. # # A trafo may also be {None}, representing the identiy # function on {\RX}. def identity(): # Returns a representation of the identity transformation,, namely {None}. return trafo_IMP.identity() def inv(T): # Returns a representation of the inverse of the trafo {T}. return trafo_IMP.inv(T) def compose(TL): # The argument {TL} must be a list or tuple of zero or more trafos. # Returns a representation of the composition # of those trafos, applied in that order. return trafo_IMP.compose(TL) def nfactors(T): # The argument {T} must be a trafo. Returns the number of factors # that appear in the representation of {T}. # # Specifically, if {T} is {None}, returns 0. If {T} is a {Trafo} object, returns 1. # Otherwise {T} must be a tuple {(s,...)} where {s} is {+1} or {-1}; then # the procedure returns 1 less than the length of that tuple. return trafo_IMP.nfactors(T) def factor(T,k): # The arguments {T} and {k} must be a trafo and an integer in {0..n-1} # where {n = nfactors(T)}. Returns the factor of {T} with index {k}. # # Specifically, if {n} is zero, the procedure fails. If {T} is # a {Trafo} object and {k=0}, returns {T}. Otherwise {T} must be a tuple # {(s,...)} where {s} is {+1} or {-1}; then the procedure returns # {T[k+1]} or {inv(T[n-1-k])}, respectively. return trafo_IMP.factor(T,k) def is_identity(T): # If the procedure can determine that {T} is the identity -- for example if # {T} is {None} or {[+1]} -- returns {True}. Otherwise (if {T} is NOT the identity, # or the procedure can't determine) it returns {False}. return trafo_IMP.is_identity(T) def simplify(T): # Applies some heuristic rules to reduce {T} to the # simplest possible form. # # If it can determine that {T} is the identity, returns {None}. If it # can reduce {T} to a single {Trafo} object, returns that object. # Otherwise returns a tuple {(+1,T1,T2,...,Tn)} where each {Ti} is either # {Oi} or a pair {(-1,Oi)} where {Oi} is a {Trafo} object. return trafo_IMP.simplify(T) def to_string(T): # Returns a string representation of {T}. {None} is # represented as "*", a {Trafo} object is represented by # its name, and other types are represented as "(i T1 T2...)" # where {i} is the inversion bit and {T1,T2} are # the string representations of its factors, in the order # they are stored. return trafo_IMP.to_string(T)