)abbrev domain MOEBIUS MoebiusTransform
++ 2-by-2 matrices acting on P1(F).
++ Author: Stephen "Say" Watt
++ Date Created: January 1987
++ Keywords:
++ Examples:
++ References:
MoebiusTransform(F) : Exports == Implementation where
  ++ MoebiusTransform(F) is the domain of fractional linear (Moebius)
  ++ transformations over F.
  F : Field
  OUT ==> OutputForm
  P1F ==> OnePointCompletion F         -- projective 1-space over F

  Exports ==> Group with

    moebius : (F, F, F, F) -> %
      ++ moebius(a, b, c, d) returns \spad{matrix [[a, b], [c, d]]}.
    shift : F -> %
      ++ shift(k) returns \spad{matrix [[1, k], [0, 1]]} representing the map
      ++ \spad{x -> x + k}.
    scale : F -> %
      ++ scale(k) returns \spad{matrix [[k, 0], [0, 1]]} representing the map
      ++ \spad{x -> k * x}.
    recip : () -> %
      ++ recip() returns \spad{matrix [[0, 1], [1, 0]]} representing the map
      ++ \spad{x -> 1 / x}.
    shift : (%, F) -> %
      ++ shift(m, h) returns \spad{shift(h) * m}
      ++ (see \spadfunFrom{shift}{MoebiusTransform}).
    scale : (%, F) -> %
      ++ scale(m, h) returns \spad{scale(h) * m}
      ++ (see \spadfunFrom{shift}{MoebiusTransform}).
    recip : % -> %
      ++ recip(m) = recip() * m
    eval : (%, F) -> F
      ++ eval(m, x) returns \spad{(a*x + b)/(c*x + d)}
      ++ where \spad{m = moebius(a, b, c, d)}
      ++ (see \spadfunFrom{moebius}{MoebiusTransform}).
    eval : (%, P1F) -> P1F
      ++ eval(m, x) returns \spad{(a*x + b)/(c*x + d)}
      ++ where \spad{m = moebius(a, b, c, d)}
      ++ (see \spadfunFrom{moebius}{MoebiusTransform}).

  Implementation ==> add

    Rep := Record(a : F, b : F, c : F, d : F)

    moebius(aa, bb, cc, dd) == [aa, bb, cc, dd]

    a(t : %) : F == t.a
    b(t : %) : F == t.b
    c(t : %) : F == t.c
    d(t : %) : F == t.d

    1 == moebius(1, 0, 0, 1)
    t * s ==
      moebius(b(t)*c(s) + a(t)*a(s), b(t)*d(s) + a(t)*b(s), _
              d(t)*c(s) + c(t)*a(s), d(t)*d(s) + c(t)*b(s))
    inv t == moebius(d(t), -b(t), -c(t), a(t))

    shift f == moebius(1, f, 0, 1)
    scale f == moebius(f, 0, 0, 1)
    recip() == moebius(0, 1, 1, 0)

    shift(t, f) == moebius(a(t) + f*c(t), b(t) + f*d(t), c(t), d(t))
    scale(t, f) == moebius(f*a(t), f*b(t), c(t), d(t))
    recip(t : %) : % == moebius(c(t), d(t), a(t), b(t))

    eval(t : %, f : F) == (a(t)*f + b(t))/(c(t)*f + d(t))
    eval(t : %, f : P1F) ==
      (ff := retractIfCan(f)@Union(F,"failed")) case "failed" =>
        (a(t)/c(t)) :: P1F
      zero?(den := c(t) * (fff := ff@F) + d(t)) => infinity()
      ((a(t) * fff + b(t))/den) :: P1F

    coerce t ==
      var := message("%x")
      num := (a(t) :: OUT) * var + (b(t) :: OUT)
      den := (c(t) :: OUT) * var + (d(t) :: OUT)
      rarrow(var, num/den)

    proportional? : (List F, List F) -> Boolean
    proportional?(list1, list2) ==
      empty? list1 => empty? list2
      empty? list2 => false
      zero? (x1 := first list1) =>
        (zero? first list2) and proportional?(rest list1, rest list2)
      zero? (x2 := first list2) => false
      map((f1 : F) : F +-> f1 / x1, list1) = map((f1 : F) : F +-> f1 / x2, list2)

    t = s ==
      list1 : List F := [a(t), b(t), c(t), d(t)]
      list2 : List F := [a(s), b(s), c(s), d(s)]
      proportional?(list1, list2)

--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
--All rights reserved.
--
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are
--met:
--
--    - Redistributions of source code must retain the above copyright
--      notice, this list of conditions and the following disclaimer.
--
--    - Redistributions in binary form must reproduce the above copyright
--      notice, this list of conditions and the following disclaimer in
--      the documentation and/or other materials provided with the
--      distribution.
--
--    - Neither the name of The Numerical ALgorithms Group Ltd. nor the
--      names of its contributors may be used to endorse or promote products
--      derived from this software without specific prior written permission.
--
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
