Fractional Linear Transformations

Since the days of Felix Klein (around 1870), any discussion about any kind of geometry mentions the transformations that leave geometry invariant. (Abhyankar, 1990) has suggested that the proper group of transformations is the group of fractional linear transformations, or FLTs. While these generally work, we will keep the discussion simple by focusing on the plane invertible case.

This chapter includes half a dozen different functions for fractional linear transformations, all using the same basic function name, some variant of “FLT”.  For a full listing, see Appendix 2. I have also added a summary of these different functions and how they relate to the overall topic at the end of this chapter.

6.1 The Group of Fractional Linear Transformations

A fractional linear transformation is a transformation of the plane given by

F(x,y) = ((((Subscript[a, 1,1])x+(Subscript[a, 1,2])y+ (Subscript[a, 1,3]))/((Subscript[d, 1])x+(Subscript[d, 2])y+(Subscript[d, 3]))),(((Subscript[a, 2,1])x+(Subscript[a, 2,2])y+ (Subscript[a, 2,3]))/((Subscript[d, 1])x+(Subscript[d, 2])y+(Subscript[d, 3])))),

where (Subscript[a, i, j]), (Subscript[d, j]) are fixed real (or sometimes complex) numbers so that an inverse function of the same type exists.

Note that the equation (Subscript[d, 1])x+(Subscript[d, 2])y+(Subscript[d, 3])=0  defines a line. Often (Subscript[d, 1]), (Subscript[d, 2])=0, so this will be the infinite line. In either case, in the domain of the FLT, F  , as shown above, will be the set of affine points with (Subscript[d, 1])x+(Subscript[d, 2])y+(Subscript[d, 3])≠0.

The notation above suggests we describe the FLT compactly by the matrix

A=(({{(Subscript[a, 1,1]), (Subscript[a, 1,2]), (Subscript[a, 1,3])}, {(Subscript[a, 2,1]), (Subscript[a, 2,2]), (Subscript[a, 2,3])}, {(Subscript[d, 1]), (Subscript[d, 2]), (Subscript[d, 3])}})).

This is more compact as well as useful because the FLT is actually given by this two-step procedure using matrix multiplication:

{x,y} ↦ A(({{x}, {y}, {1}})) = {u,v,w} ↦{(u/w), (v/w)}

flt[{x_,y_},A_]:=Module[{u,v,w},
{u,v,w}= A.{x,y,1};
If[Abs[w]<1.*^-6,{},{u/w,v/w}]]

A={{1,0,-2},{0,-1,0},{0,1,1}};
A//MatrixForm

p=RandomReal[{-3,3},2]

q=flt[p,A]

flt[q,Inverse[A]]

B=RandomInteger[{-5,5},{3,3}]

flt[p, B.A]
flt[q,B]

We can generalize the following for invertible matrices A, B:

The composition of two FLTs is an FLT; in particular, the composition of the FLT given by matrix A with the FLT given by matrix B is the FLT given by the matrix product B A.

The FLT ℐ defined by the identity matrix is the identity transformation; that is, ℐ[x,y]={x,y} for all {x,y}.

Each FLT has an inverse FLT, and the inverse of the FLT given by A is (A^(-1)).

These facts can by defined as the set of FLTs in a group of transformations.

We have failed to mention a technicality: if we multiply a matrix by a nonzero constant c, that is

c A = (({{c, 0, 0}, {0, c, 0}, {0, 0, c}}))A,

then we still get the same FLT due to the division at the end, so the group of FLTs is not the group of invertible 3×3 matrices but rather the group quotient by the nonzero constant diagonal matrices.

A
flt[{2,-1},A]

This means that the point {2,-1} was not in the domain of the FLT defined by A. For this matrix, (Subscript[d, 1])=0,(Subscript[d, 2])=(Subscript[d, 3])=1 is giving the line (Subscript[d, 1])x+(Subscript[d, 2])y+(Subscript[d, 3])=y+1=0 as the affine line not in the domain. The routine flt returns the empty list in this case.

In fact, these FLTs easily extend to the entire projective plane. The formula is actually simpler since the FLT given by A simply sends the projective point

{x,y,z} ↦ A (({{x}, {y}, {z}})).

In this case, the fact that the point is only defined up to a nonzero constant multiple complements the fact that matrix A is also only defined up to a nonzero constant multiple.

flti[p_,A_] :=Module[{u,v,w},
If[Length[p]==2, {u,v,w}= A.Append[p,1], {u,v,w}= A.p];
If[Abs[w]<1.*^-6, {u,v,0}, {u/w,v/w}]]

Unlike the affine FLT, the projective FLTs are defined on the entire projective plane. The points of the affine plane, where the affine FLT was not defined, now go to the infinite line. In the previous example using flti, p could be either affine or projective. The output will be affine if the result is not infinite or projective otherwise.

flti[{3,2},A]

flti[{3,2,1},A]

flti[{2,-1},A]

flti[{2,-1,1},A]

We will see that if, in the original formula, (Subscript[d, 1])=(Subscript[d, 2])=0, then the FLT leaves the infinite line alone and simply transforms the affine plane. These transformations may be familiar to you from elementary transformational geometry.

Later in this chapter, we will also consider FLTs defined by matrices with complex entries. These work the same way, but now the group of transformations is known as PGL(2,ℂ). Unless noted otherwise, you can assume that we are talking about real FLTs.

6.2 The Action of FLT on Curves

The most important property of FLTs is that they act on curves as well as points. Again, we do the special plane invertible case only. One key is that the denominator in the formula (6.1) is the same for both coordinates, so passing to the projective case, we can use coordinate z for the denominator. Thus, projectively, the FLTs are polynomial transformations, not rational transformations.

Given an FLT F(p) and a curve f(x,y)=0, we want a new curve g(x,y)=0 with the property that if each point p on f=0, then g(F (p))=0; that is, F (p) is on the curve g=0, and conversely, if q is on the curve g=0, then there is a unique point p on f=0 with F (p)=q, but invertibility of F  implies that p=(F^( -1))(q). Hence we conclude that our formula for g should be

g (x,y) = f((F^( -1))(x,y)).

Working affinely, we have the problem that since (F^( -1)) is a rational transformation, we will be getting denominators that are no longer the same, causing problems numerically since we cannot assume simplification, but we can avoid this by working projectively. Assume F  is given by matrix A and the homogenization of the curve is the homogeneous polynomial h(x,y,z). Then the new projective curve is given by

g(x,y,z) = h((A^( -1)) (x,y,z)).

FLTh[h_,A_,x_,y_,z_] :=Expand h/.Thread[{x,y,z}->Inverse[A].{x,y,z}];

h= x^2+y^2-4z^2;
A={{1,0,2},{0,1,3},{0,0,1}};
k=FLTh[h,A,x,y,z]

Here, h is the homogenization of (x^2)+(y^2)=4, but the specialization of k at z=1 is just (((x-2))^2) + (((y-3))^2) = 4.

flth[p_,A_]:=A.p;

flth[{2,2,Sqrt[2]},A]

As suggested by the example above, the affine case is now handled by homogenizing f , transforming by FLTh and finally specializing at z=1.

FLT[f_,A_,x_,y_]:=Module[{fh,gh, AI,B,d,z},
fh=homog[f,x,y,z];
AI=Inverse[A];
B=AI.{x,y,z};
gh=Expand[fh/.Thread[{x,y,z}->B]];
Chop[gh/.{z->1},1*^-10]
];

A={{1,0,2},{0,1,3},{0,0,1}};
g=FLT[x^2+y^2-4, A,x,y]

If an FLT takes curve f=0 to curve g=0, then we say f and g are equivalent projective curves. Although they may look different in the affine plane, the FLT is a polynomial map in the projective plane and hence continuous. Moreover, the fact that the projective FLT is invertible makes it 1-1 and onto. In particular, all topological properties are preserved. It is not difficult to show the projective graphs, as defined in Chapter 5, are also preserved. Thus, from a geometer’s point of view, they are the same. We will see a number of examples in the next section.

6.3 Examples of FLTs

In this section, we will look at various subgroups of the FLT group; that is, sets of transformations that are closed under composition and taking inverses. Each subgroup defines a different kind of plane geometry. We will develop this material further in Chapter 7.

The Euclidean Group

An FLT defined by matrix A is Euclidean if the last row is {0,0,1} and the determinant is ±1. FLTs in the Euclidean group take the affine plane to the affine plane and the infinite line into the infinite line.

Translations: If we think of the affine plane as a vector space, a translation adds a constant vector to each point. A translation is defined by the image of a single point. The product of two translations is a translation, as is the inverse.

PQTranslation[p_,q_]:={{1,0,q[[1]]-p[[1]]},{0,1,q[[2]]-p[[2]]},{0,0,1}};

A=PQTranslation[{2,3},{5,2}];
A //MatrixForm

Inverse[A]//MatrixForm

Rotations: The standard clockwise rotation around the origin in θ radians is given by the matrix

(({{Cos[θ], -Sin[θ], 0}, {Sin[θ], Cos[θ], 0}, {0, 0, 1}})).

However, for our purposes, it is more useful to define a rotation by giving two intersecting affine lines, considering the rotation around the intersection point and taking the first line to the second line. The code makes use of the built-in Mathematica function RotationMatrix.

If we restricted ourselves to FLTs with rational matrices, we would not be able to construct these FLTs, even from lines defined by integer coefficients. This is perhaps the biggest single argument for doing curve theory numerically.

klRotation[k_,l_,x_,y_]:= Module[{p,a1,a2,b1,b2,T,R, A,B,m},
a1=Coefficient[k,x];
b1=Coefficient[k,y];
a2=Coefficient[l,x];
b2=Coefficient[l,y];
If[Abs[a1*b2-a2*b1]< 1.*^-9,Print["No affine center"];
Return[Fail]];
p={x,y}/.NSolve[{k,l}][[1]];
T={{1,0,-p[[1]]},{0,1,-p[[2]]},{0,0,1}};
R=N[RotationMatrix[{{a1,b1},{a2,b2}}]];
R=Join[Append[R,{0,0}],{{0},{0},{1}},2];
Inverse[T].R.T
]

R=klRotation[2x+3y+1,x-y+2,x,y];

R//MatrixForm

Inverse[R]//MatrixForm

Again, since the intersection of the two lines is not the origin, this rotation matrix is also not a linear transformation of the plane. However, note that the upper left 2×2 submatrix in (R^(-1)) is the transpose of that in R.

Reflections: The reflection in the x-axis takes point {a,b} to {a,-b}. This reflection is its own inverse. The best way to reflect about an arbitrary line is to use translations and rotations to move an arbitrary line to the x-axis, reflect and then move back. This combined operation is called conjugation in group theory.

kReflection[k_,x_,y_]:=Module[{a,b,c,T,RX,RO},
RX={{1,0,0},{0,-1,0},{0,0,1}};
a=Coefficient[k,x];
b=Coefficient[k,y];
c=k/.Thread[{x,y}->{0,0}];
If[a==0,
T=PQTranslation[{0,0},{0,-c/b}];
Return[T.RX.Inverse[T]],
RO=klRotation[y,k,x,y];
Return[RO.RX.Inverse[RO]];
]
]

A=kReflection[x-y,x,y]

B=kReflection[3x-2y-1,x,y]

B//MatrixForm
Inverse[B]//MatrixForm

Note that even though the line is not through the origin, the reflection FLT is its own inverse.

Generally speaking, any Euclidean transformation is a composition of the above three types. A Euclidean transformation is determined uniquely by taking the three noncolinear vertices of a triangle to corresponding vertices of a congruent triangle. In fact, it is enough to use two or three reflections. We will illustrate this in Chapter 7 by showing how to take any affine ellipse to an ellipse of the form ((x^2)/(a^2))+((y^2)/(b^2))-1=0.

If one includes similarity transformations with matrices of the form

(({{r, 0, 0}, {0, r, 0}, {0, 0, 1}})),

when r>0, one gets the group of Euclidean similarities. With these, you can transform any triangle to a given similar triangle.

Affine Transformations

The word “affine” comes from “affine transformations,” which are transformations that take Euclidean lines to Euclidean lines; specifically, an FLT defined by the matrix

A=(({{(Subscript[a, 1,1]), (Subscript[a, 1,2]), (Subscript[a, 13])}, {(Subscript[a, 2,1]), (Subscript[a, 2,2]), (Subscript[a, 2,3])}, {0, 0, 1}})),

where (Subscript[a, 1, 1])(Subscript[a, 2, 2])-(Subscript[a, 1, 2])(Subscript[a, 2, 1])≠0. In particular, the group of affine transformations contains the Euclidean and similarity transformations. There are two new types that, with the Euclidean transformations, generate the entire group.

Shears: The standard shear leaves the x-coordinate fixed while shrinking or expanding the y-coordinate so that a given line l intersecting the x-axis is moved to the x-axis.

kShear[k_,x_,y_]:=Module[{a,b,c,d,e},
c=Coefficient[k,x];
d=Coefficient[k,y];
e=k/.{x->0,y->0};
a=-e/d;
b=-c/d;
{{1,0,0},{-b,1,-a},{0,0,1}}
]

A=kShear[x+y,x,y];
A //MatrixForm

S={{0,0},{1,0},{1,1},{0,1},{0,0}};
S1=flt[#,A]&/@S
{Show[ListLinePlot[S, AspectRatio->1,PlotRange->{{-.5,1.5},{-.5,2.2}},PlotStyle->Thick],ListPlot[{Labeled[{0,0},"A",{Bottom,Left}],Labeled[{1,0},"B",{Bottom,Right}],Labeled[{1,1},"C",{Top,Right}], Labeled[{0,1},"D",{Top,Left}]}]], Show[ListLinePlot[flt[#,A]&/@S,PlotRange->{{-.5,1.5},{-.5,2.2}},AspectRatio->1,PlotStyle->Thick],ListPlot[{Labeled[flt[{0,0},A],"A'",{Bottom,Right}],Labeled[flt[{1,0},A],"B'",{Bottom,Left}],Labeled[flt[{1,1},A],"C'",{Top,Left}],Labeled[flt[{0,1},A],"D'",{Top,Right}]}]]}

A shear takes the line x=y to the y-axis, point A to point A', etc. In both examples, notice what happens to points B, C, and D; noting that point A stays fixed at the origin.

Homothety: Also in the affine group is the homothety given by the matrix

(({{r, 0, 0}, {0, s, 0}, {0, 0, 1}})),

where r and s are positive reals.

homothety[r_, s_] := {{r, 0, 0}, {0, s, 0}, {0, 0, 1}};

B= homothety[2,.5]
S={{0,0},{1,0},{1,1},{0,1},{0,0}};

SS=flt[#,B]&/@S

ListLinePlot[{S,SS},Axes->False,Frame->True, PlotStyle->{Blue,Orange}]

Now you can construct any affine transformation using the Euclidean, shear or homothety transformations.

Some Projective Transformations

As mentioned earlier, the full projective linear group consists of all FLTs. There are two that will generally be useful in the next two chapters that will be mentioned here. The first is the ip2z transform, which takes an infinite point and places it at the origin. The second, iTransform, places affine line ℓ at infinity. Both of these place the infinite line at the x-axis.

ip2z[ip_,x_,y_]:=Module[ {p,l,A,B},
If[Length[ip] ≠ 3,Print["not infinite point"];Abort[],If[Abs[ip[[3]]]>1.*^-6,Print["not infinite point"];Abort[],p=Chop[ip,1.*^-6]]];
B={{1.414213562373095`,0.`,0.`},{0.`,0.`,1.414213562373095`},{0.`,-0.7071067811865475`,-0.7071067811865475`}};
If[Abs[p[[1]]]<1.*^-6,Return[B]];
ral=line[p,{0,0},x,y];
B.klRotation[l,x,x,y]]

rrit1={-0.7812879011987071`,-0.3168196688992504`,0.9191639531555853`};
rrit2=1.4009431979825675`;
iTransform[l_,x_,y_]:= Module[{ph},
ph=N[{Coefficient[l,x],Coefficient[l,y], l/.Thread[{x,y}->{0,0}]}];
ph=ph/Norm[ph];
{rrit1,{0,0,rrit2},ph}];

Programming note: iTransform uses random numbers rrit1, rrit2. On this page, they are set to specific random numbers. In Appendix 2, they are set once per initialization. Thus using this function out of this specific context may give different answers.

ContourPlot[{x y ==1,x-y==0,x+y==0}, {x,-5,5},{y,-5,5}]

A=ip2z[{0,1,0},x,y]

B1=iTransform[x-y,x,y]

B2=iTransform[x+y,x,y]

f=x y-1;

g=FLT[f,N[A],x,y]

h1=FLT[f,B1,x,y]

h2=FLT[f,B2,x,y]

{ContourPlot[{g==0,y==0}, {x,-5,5},{y,-5,5},ContourStyle->{Blue,Dashed},ImageSize->Small],ContourPlot[{h1==0,y==0}, {x,-2,2},{y,-2,2},ContourStyle->{Blue,Dashed}, ImageSize->Small],
ContourPlot[{h2==0,y==0}, {x,-2,2},{y,-2,2},ContourStyle->{Blue,Dashed},ImageSize->Small]}

In these examples, the dashed line is the original infinite line. In the first case, ip2z shows the intersection of the hyperbola with the infinite line at {0,1,0}. The infinite line is now at the origin, but the intersection with {1,0,0} remains infinite under the transformation and the transformed equation is actually a parabola. In the second of the two cases, both of the original infinite points are shown, but we get a hyperbola (or ellipse, depending on whether the removed line intersects the original hyperbola in two or zero points). It was Johann Kepler who first noted in 1604 that the parabola, hyperbola and ellipse were the same except for the number of infinite points. We will say more on conics and rational function curves in Chapter 7.

6.4 Applications

I will give three important applications of FLTs here. In the next chapter, I will give applications to classical mathematics.

Projective Singular Points

In Chapter 5, we saw that it was important to find all complex projective singular points in order to decide if a curve is nonsingular. To properly describe the projective graph of a curve, it is necessary to have at least all real projective singular points. The method of Chapter 5 required checking for singular points in all three specializations. Using FLTs, we will see that it is usually enough to check once. The strategy is to pick a random affine line and remove it from the projective plane. We get the image of this specialization by using FLT. We then use the procedure below for finding all complex affine singular points. This procedure has a fourth parameter, eps, which gives a tolerance. If you think the curve has no singular points, use a very loose tolerance such as eps=.01 to be sure you get all the singular points available. If the result is the empty set { }, you can be fairly confident that the curve is nonsingular. However, you may get some false singular points, but by decreasing the tolerance, the false ones will be eliminated. Also note that singular points that appear on one run of the algorithm but not others are probably false, but be careful with infinite points that are only defined up to a constant.

Note that the last third of this procedure is devoted to displaying the points nicely, encouraging infinite singular points to display as infinite and real points to display as real.

complexProjectiveSingularPoints[h_,u_,v_,eps_]:=Module[{f,w,A,a,b,sol1,sol2,solz,sing,sing1,sing2},
A={RandomReal[{-1,1},3],{0,0,RandomReal[{1,2}]},RandomReal[{-1,1},3]};
f=FLT[h,A,u,v];
{a,b}=RandomComplex[{-1-I,1+I},2];
sol1={u,v}/.NSolve[{f,a D[f,u]+b D[f,v]}];
{a,b}=RandomComplex[{-1-I,1+I},2];
sol2={u,v}/.NSolve[{f,a D[f,u]+b D[f,v]}];
solz=Join[sol1,sol2];
sing=Flatten[Take[Select[Tally[solz,Norm[#1-#2]<eps&],#[[2]]>1&],All,1],1];
sing1=Table[{sing[[j,1]],If[Abs[sing[[j,2]]]>eps,sing[[j,2]],0]},{j,Length[sing]}];
sing2=flti[#,Inverse[A]]&/@sing1;
sing2=Table[Which[Length[p]==2,p,Abs[p[[1]]]>eps,p/p[[1]],Abs[p[[2]]]>eps,p/p[[2]],True,{0,0,p[[3]]}],{p,sing2}];
Chop[sing2,eps]];

fs=-1-x y+(x^3) y;

sing=complexProjectiveSingularPoints[fs,x,y,.1]

ContourPlot[fs==0,{x,-5,5},{y,-5,5}]

sing=complexProjectiveSingularPoints[f,x,y,.0001]

Our next examples involve perturbing curve g slightly. In the affine real case, we saw that a small perturbation of a curve with a singular point often made the singular point appear to vanish. We now explore the complex projective case.

g=-1+(x^2)-2 (x^3)-y+(x^2) y;
h=-0.9975`+(x^2)-2 (x^3)-0.9925` y+(x^2) y+0.0075` (y^2)+0.0025` (y^3);

singg=complexProjectiveSingularPoints[g,x,y,.01]
singh =complexProjectiveSingularPoints[h,x,y,.01]

singg=complexProjectiveSingularPoints[g,x,y,.000001]
singh =complexProjectiveSingularPoints[h,x,y,.000001]

Here, g has an infinite singular point, but h, which is g with a small perturbation, has no singular points, real or complex.

Projective Complex Intersection Points

The same technique works for finding all the complex projective intersection points of two curves.

complexProjectiveIntersectionpoints[f_,g_,x_,y_]:=Module[{f1,g1,A,sol, sol2},
A={RandomReal[{-1,1},3],{0,0,RandomReal[{1,2}]},RandomReal[{-1,1},3]};
f1=FLT[f,A,x,y];
g1=FLT[g,A,x,y]; 
sol={x,y}/.NSolve[{f1,g1}];
flti[#,Inverse[A]]&/@sol];

f=-4-20 x+(x^2)+(x^3)+(x^5)-(y^2)-3 x (y^2)-10 (x^3) (y^2)+5 x (y^4);
g=16 x-8 (x^3)+(x^5)+24 x (y^2)-10 (x^3) (y^2)+5 x (y^4);

ContourPlot[{f==0,g==0},{x,-4,4},{y,-4,4}]

L=Chop[complexProjectiveIntersectionpoints[f,g,x,y],1.*^-6]
Length[L]

Li=Tally[Select[L,Length[#]==3&],Norm[#1-#2]<.01&]
La=Tally[Select[L,Length[#]==2&],Norm[#1-#2]<.01&]

We conclude there are, as Bézout tells us, 25 intersection points counted by multiplicity. These include five real infinite points, one {0,1,0} of multiplicity 3 and four of multiplicity 2. There are two real affine intersection points {±2,0} of multiplicity 2, two complex affine multiple two-intersection points {0,±2i} and three pairs of complex conjugate affine simple intersection points.

Note that finding intersection points is more stable than finding singular points. complexProjectiveIntersectionpoints does not require a tolerance, and usually, running it once is enough. It is better to use this second function to find singular points that come from intersections.

Constructions with Curves

One way to make interesting new curves from old curves is to add or subtract infinite points by removing an affine line ℓ using iTransform. The new infinite points correspond to the affine points on ℓ while infinite points not on ℓ become affine points.

Newton observed that there were cubic curves with four affine components. We saw this with Newton hyperbolas. Another way to construct such a curve is to start with a common cubic such as

f=(y^2)-(x^3)+x;

and remove a line ℓ intersecting the infinite component in two chosen real points. We can see, as Bézout determined, it will also intersect in an additional point that must also be real and in the infinite (versus the finite) component.

l=10x-y-20

A=iTransform[l,x,y]
h=FLT[f,A,x,y]
{ContourPlot[{f==0,l==0}, {x,-4,4},{y,-4,4}], ContourPlot[h==0,{x,-8,8},{y,-8,8}]}

Programming note: Since iTransform is partially random, the curve will come out differently when you run this example. The curve will still have four affine components, but you may have to adjust the scale in order to be able to see them.

Projective real curves of even degree can often be represented by affine curves with no infinite points. We will see in Chapter 9 that this is not true of odd degree curves. This is easy to check if you can find a line that does not intersect the curve in a real projective point.

g= gaussCurve[z^6-6z+6,x,y,z]

B=iTransform[y,x,y]

g1=FLT[g,B,x,y];
{ContourPlot[{g==0,y==0},{x,-6,6},{y,-6,6}],ContourPlot[g1==0, {x,-6,6},{y,-10,10}]}

h=gaussCurve[(z^2-1)(z^2-4)(z^2-9),x,y,z]

A=iTransform[x,x,y]

h1=FLT[h,A,x,y];
{ContourPlot[{h==0,x==0},{x,-6,6},{y,-6,6}],ContourPlot[h1==0, {x,-4,4},{y,-3,3}]}

In Chapter 9, we call the innermost oval a depth 2 oval since it is contained in the interior of a curve component, which itself is contained in the interior of a curve component.

6.5 Summary of Fractional Linear Transformations

The single idea of transforming curves has several different facets. We can give the transformation as a function or use a matrix representation. Since we can represent a curve as an equation, bivariate polynomial or a point set, we can transform either. Further, we can decide if we want to transform just affine points or if we want to include infinite points. In the latter case, we can still work primarily in the affine plane or move to the projective plane.

As a function on the affine plane, a fractional linear transformation is given as

F(x,y) = ((((Subscript[a, 1,1])x+(Subscript[a, 1,2])y+ (Subscript[a, 1,3]))/((Subscript[d, 1])x+(Subscript[d, 2])y+(Subscript[d, 3]))),(((Subscript[a, 2,1])x+(Subscript[a, 2,2])y+ (Subscript[a, 2,3]))/((Subscript[d, 1])x+(Subscript[d, 2])y+(Subscript[d, 3])))).

The domain is the plane subset where the denominator is not zero, which is either the plane or the plane with a single line removed. This may be represented in matrix form:

A=(({{(Subscript[a, 1,1]), (Subscript[a, 1,2]), (Subscript[a, 1,3])}, {(Subscript[a, 2,1]), (Subscript[a, 2,2]), (Subscript[a, 2,3])}, {(Subscript[d, 1]), (Subscript[d, 2]), (Subscript[d, 3])}}))

F: {x,y} ↦ A(({{x}, {y}, {1}})) = {u,v,w} ↦{(u/w), (v/w)}

This is consistent with transformations in the Wolfram Language. See the documentation pages for the Wolfram Language functions TransformationMatrix and Transformation for more information.

Our matrices agree, in the affine case, with TransformationMatrix, and one can generally represent the transformation that works on points using either flt or the Transformation function.

A={{-2,2,7},{-1,-6,0},{3,3,8}};
p={3.4552977152086983`,-3.719873903204607`};
flt[p,A]
TransformationFunction[A][p]

q={-3 ,1/3};
flt[q,A]
TransformationFunction[A][q]

FLT[y-x^2,A,x,y]
FLT[y-x^2,N[A],x,y]

q1=flti[q,A]
flti[q1,Inverse[A]]

flth[Append[p,1],A]
flth[Append[q,1],A]

FLTh[y z-x^2,A,x,y,z]

flts[{Cos[t],Sin[t]},A]