# This function is a homeomorphism from F16 to [0,1]^2 given by
# quadratic polynomials. However, the inverse is not differentiable
# along the boundary of [0,1]^2, so it is not a diffeomorphism.
#@ square_homeo
square_homeo := (x) -> [
x[3]*(x[3] - x[4]/sqrt(2)),
x[2]*(x[2] - x[1]) + x[4]*(x[4] - sqrt(2)*x[3])
];
#@ square_homeo_cone_a
square_homeo_cone_a := (s,t) ->
[2*cos(t),cos(t+s)+cos(t),sqrt(2)*sin(t),-sin(t+s)+sin(t)];
######################################################################
# This function gives a smooth embedding from a open neighbourhood of
# F16 in EX^* to a neighbourhood of [0,1]^2 in R^2. It restricts to
# give a diffeomorphism from F16 to [0,1]^2. The second component is
# a quadratic polynomial, but the first term has some cubic terms and
# some quadratic terms.
#@ sd_alpha
sd_alpha[0] := (x) -> x[3] - x[4]/sqrt(2) + x[1]^2 + x[4]^2 + x[3] * (x[4] - x[2])/sqrt(2);
sd_alpha[1] := (x) -> ((3/4)*sqrt(2)-1)*x[1]+x[2]-x[3]-sqrt(2)*x[4];
sd_alpha[2] := (x) -> x[1] - 3/4*sqrt(3)*x[3] + (3 - 3/4*sqrt(6))*x[4];
#@ square_diffeo_E0
square_diffeo_E0 := (x) -> [
x[3] * sd_alpha[0](x) - x[2]^2 * x[4],
(x[2]-x[1]) * sd_alpha[1](x) +
x[4] * sd_alpha[2](x)
];
# Here is a different diffeomorphism, which may actually be better.
#@ square_diffeo_E0_alt
square_diffeo_E0_alt :=
(x) -> [x[3]/(x[2]+x[3]),
((x[1]-x[2])*(1-2*x[1]-2*x[2])-3*sqrt(2)*x[3]*x[4])/(2+2*x[1]-x[2])];
#@ square_diffeo_E0_alt_inv_approx
square_diffeo_E0_alt_inv_approx := (t) ->
[-(247/164)*t[2]^2*t[1]^2+(129/455)*t[2]^2*t[1]+(192/83)*t[2]*t[1]^2-(62/921)*t[2]^2-(303/790)*t[1]*t[2]-(113/140)*t[1]^2-(119/186)*t[2]+(349/3489)*t[1]+169/239, -(127/234)*t[2]^2*t[1]^2+(386/411)*t[2]^2*t[1]+(254/315)*t[2]*t[1]^2-(379/956)*t[2]^2-(347/232)*t[1]*t[2]-(113/140)*t[1]^2+(375/544)*t[2]+(349/3489)*t[1]+169/239, (695/2213)*t[2]^2*t[1]^2-(373/1262)*t[2]^2*t[1]-(173/240)*t[2]*t[1]^2+(179/345)*t[1]*t[2]-(154/383)*t[1]^2+(537/383)*t[1], -(1013/1124)*t[2]^2*t[1]^2+(298/299)*t[2]^2*t[1]+(165/112)*t[2]*t[1]^2-(294/137)*t[1]*t[2]];
#@ square_diffeo_E0_alt_inv
square_diffeo_E0_alt_inv := proc(t::RR0_2)
local x,x0,x1,sol;
x0 := [x[1],x[2],x[3],x[4]];
x1 := evalf(square_diffeo_E0_alt_inv_approx(t));
sol := fsolve(
[op(square_diffeo_E0_alt(x0) -~ t),rho(x0)-1,g0(x0)],
{x[1] = x1[1],x[2] = x1[2],x[3] = x1[3],x[4] = x1[4]}
);
return subs(sol,x0);
end:
######################################################################
# This function finds the preimage under square_diffeo_E0 of a specified point
# in [0,1]^2 by an iterative search. I am not sure whether this is actually
# better than using fsolve(). I previously had some problems with fsolve(),
# but I think that they may have been caused by a misunderstanding about
# the behaviour of evalf[n](...).
#@ square_diffeo_E0_inverse_search
square_diffeo_E0_inverse_search := proc(t0::[numeric,numeric])
local s,s0,tol,n,i,e,u,uu,n0,x0,dx,b0,db,sda,sdj,J0,err;
# We handle points on the boundary of the square separately, to ensure that
# we get points that lie exactly on the corresponding loci in EX^*.
if t0[1] = 0 then
if t0[2] = 0 then
return v_E1[6];
elif t0[2] = 1 then
return v_E1[3];
else
s0 := fsolve(square_diffeo_E0(c_E0[0](s))[2] = t0[2],s=evalf(Pi/4*(1+t0[2])));
return evalf(c_E0[0](s0));
fi;
elif t0[1] = 1 then
if t0[2] = 0 then
return v_E1[0];
elif t0[2] = 1 then
return v_E1[11];
else
s0 := fsolve(square_diffeo_E0(c_E0[5](s))[2] = t0[2],s=evalf(Pi*t0[2]));
return evalf(c_E0[5](s0));
fi;
else
if t0[2] = 0 then
s0 := fsolve(square_diffeo_E0(c_E0[1](s))[1] = t0[1],s=evalf(Pi/2*(1-t0[1])));
return evalf(c_E0[1](s0));
elif t0[2] = 1 then
s0 := fsolve(square_diffeo_E0(c_E0[3](s))[1] = t0[1],s=evalf(Pi/2*(1-t0[1])));
return evalf(c_E0[3](s0));
fi;
fi;
# The rest of this function handles the general case, where t0 is
# not on the boundary of the square.
x0 :=
[-2.05850*t0[1]^2*t0[2]^2+0.918130*t0[1]*t0[2]^2+2.66136*t0[1]^2*t0[2]-0.115622*t0[2]^2-
0.813875*t0[1]*t0[2]-0.602855*t0[1]^2-0.591483*t0[2]-0.104250*t0[1]+0.707105,
0.129961*t0[1]^2*t0[2]^2+0.254890*t0[1]*t0[2]^2-0.479913*t0[1]^2*t0[2]-0.384851*t0[2]^2-
0.197833*t0[1]*t0[2]-0.602855*t0[1]^2+0.677745*t0[2]-0.104250*t0[1]+0.707105,
-0.492388*t0[1]^2*t0[2]^2+0.473871*t0[1]*t0[2]^2+0.818861*t0[1]^2*t0[2]-
0.983847*t0[1]*t0[2]-0.825307*t0[1]^2+1.82530*t0[1],
-1.95651*t0[1]^2*t0[2]^2+2.15931*t0[1]*t0[2]^2+2.30924*t0[1]^2*t0[2]-3.08939*t0[1]*t0[2]];
sda := unapply(evalf(expand([op(square_diffeo_E0(xx)),rho(xx) - 1,g0(xx)])),x):
sdj := unapply([seq(map(diff,sda(x),x[i]),i=1..4)],x):
x0 := Vector(x0);
b0 := Vector([op(t0),0,0]);
db := b0 - Vector(sda(x0));
n := 100;
tol := 10.^(-95);
err := Norm(db);
while err > tol and n > 0 do
n := n-1;
J0 := Transpose(Matrix(sdj(x0)));
dx := LinearSolve(J0,db);
x0 := x0 + dx;
db := b0 - Vector(sda(x0));
err := Norm(db);
od:
return convert(x0,list);
end:
######################################################################
# This function tabulates some values of the inverse of square_diffeo_E0(),
# and computes a Chebyshev approximation to that inverse.
#@ find_square_diffeo_E0_inverse
#@ square_diffeo_E0_inverse_order
#@ square_diffeo_E0_inverse
#@ square_diffeo_E0_inverse_table
#@ square_diffeo_E0_inverse_chebyshev_table
find_square_diffeo_E0_inverse := proc(NN::posint)
global square_diffeo_E0_inverse_order,square_diffeo_E0_inverse,
square_diffeo_E0_inverse_table,
square_diffeo_E0_inverse_chebyshev_table;
local CP,SDI,i,j,k,l,m,x0,sol,aa;
square_diffeo_E0_inverse_order := NN;
# CP is a table of NN+1 Chebyshev points for the interval [0,1], indexed by
# 0 to NN. Recall that all these points are actually in (0,1).
CP := table():
for i from 0 to NN do
CP[i] := evalf(1/2 + cos((2*NN-2*i+1)*Pi/(2*NN+2))/2):
od:
# It turns out to be convenient to add in the end points. These are not used
# in the Chebyshev approximation formula, but they are used to provide a
# starting point when searching for values of the inverse function.
CP[-1] := 0:
CP[NN+1] := 1:
SDI := table():
SDI[ -1, -1] := evalf(v_E0[ 6]):
SDI[NN+1, -1] := evalf(v_E0[ 0]):
SDI[ -1,NN+1] := evalf(v_E0[ 3]):
SDI[NN+1,NN+1] := evalf(v_E0[11]):
userinfo(5,genus2,"Finding edge Chebyshev points");
for i from 0 to NN do
SDI[i,-1] :=
evalf(c_E0[1](fsolve(square_diffeo_E0(c_E0[1](t))[1] - CP[i],t=0..Pi/2)));
SDI[i,NN+1] :=
evalf(c_E0[3](fsolve(square_diffeo_E0(c_E0[3](t))[1] - CP[i],t=0..Pi/2)));
SDI[-1,i] :=
evalf(c_E0[0](fsolve(square_diffeo_E0(c_E0[0](t))[2] - CP[i],t=Pi/4..Pi/2)));
SDI[NN+1,i] :=
evalf(c_E0[5](fsolve(square_diffeo_E0(c_E0[5](t))[2] - CP[i],t=0..Pi)));
od:
userinfo(5,genus2,"Finding interior Chebyshev points");
for i from 0 to NN do
for j from 0 to NN do
# x0 := SDI[i-1,j];
# sol := fsolve({op(square_diffeo_E0(x) -~ [CP[i],CP[j]]),rho(x)-1,g0(x)},{seq(x[i]=x0[i],i=1..4)});
# SDI[i,j] := subs(sol,xx);
SDI[i,j] := square_diffeo_E0_inverse_search([CP[i],CP[j]]);
od:
od:
userinfo(5,genus2,"Finding Chebyshev approximation");
aa := table():
for i from 0 to NN do
for j from 0 to NN do
for m from 1 to 4 do
aa[i,j,m] := add(add(SDI[k,l][m]*ChebyshevT(i,2*CP[k]-1)*ChebyshevT(j,2*CP[l]-1)*4/(NN+1)^2,k=0..NN),l=0..NN);
if i = 0 then aa[i,j,m] := aa[i,j,m]/2; fi;
if j = 0 then aa[i,j,m] := aa[i,j,m]/2; fi;
od:
od:
od:
square_diffeo_E0_inverse :=
unapply(expand([seq(add(add(aa[i,j,m]*ChebyshevT(i,2*t[1]-1)*ChebyshevT(j,2*t[2]-1),j=0..NN),i=0..NN),m=1..4)]),t):
square_diffeo_E0_inverse_chebyshev_table := eval(SDI);
userinfo(5,genus2,"Finding interior grid points");
square_diffeo_E0_inverse_table := table();
for i from 0 to NN do
for j from 0 to NN do
square_diffeo_E0_inverse_table[i/NN,j/NN] :=
square_diffeo_E0_inverse_search([i/NN,j/NN],square_diffeo_E0_inverse([i/NN,j/NN]));
od:
od:
NULL;
end:
##################################################
#@ save_square_diffeo_E0_inverse
save_square_diffeo_E0_inverse := proc()
save(square_diffeo_E0_inverse,
square_diffeo_E0_inverse_order,
square_diffeo_E0_inverse_table,
square_diffeo_E0_inverse_chebyshev_table,
cat(data_dir,"/embedded/roothalf/square_diffeo_E0_inverse.m"));
end:
#@ load_square_diffeo_E0_inverse
load_square_diffeo_E0_inverse := proc()
read(cat(data_dir,"/embedded/roothalf/square_diffeo_E0_inverse.m"));
end:
#@ require_square_diffeo_E0_inverse
require_square_diffeo_E0_inverse := proc()
if not type(square_diffeo_E0_inverse_order,integer) then
load_square_diffeo_E0_inverse();
fi;
end:
######################################################################
#@ make_square_diffeo_E0_inverse_plot
make_square_diffeo_E0_inverse_plot := proc()
global pics;
local T,N,i,j;
T := square_diffeo_E0_inverse_table:
N := square_diffeo_E0_inverse_order:
pics["square_diffeo_E0_inverse"] :=
display(seq(seq(op([
polygon([stereo(T[i/N,j/N]),stereo(T[(i+1)/N,j/N]),stereo(T[(i+1)/N,(j+1)/N])],style=patchnogrid),
polygon([stereo(T[i/N,j/N]),stereo(T[i/N,(j+1)/N]),stereo(T[(i+1)/N,(j+1)/N])],style=patchnogrid)]),
j=0..N-1),i=0..N-1),
axes=none,scaling=constrained);
save_plot("square_diffeo_E0_inverse");
save_jpg("square_diffeo_E0_inverse");
pics["square_diffeo_E0_inverse"];
end:
######################################################################
# This is the most general function R^2 -> R^4 with the following
# properties:
#
# 0) Each entry is polynomial with degree <= 2 in each of t[1] and t[2]
# 1) The corners of [0,1]^2 map to v[0], v[3], v[6] and v[11] in the
# usual order.
# 2) The edges are mapped in accordance with the patterns
# [0,t] |-> [x[1], x[2], 0, 0]
# [1,t] |-> [x[1], 0, x[3], x[4]]
# [t,0] |-> [x[1], x[1], x[2], 0]
# [t,1] |-> [0, x[2], x[3], -x[3]/sqrt(2)].
#
# The point is that the inverse of square_diffeo_E0 also has
# properties (1) and (2).
eqs := map(coeffs,expand([sdi([0,t[2]])[3],sdi([0,t[2]])[4],sdi([1,t[2]])[2],sdi([t[1],0])[2]-sdi([t[1],0])[1],sdi([t[1],0])[4],sdi([t[1],1])[1],sdi([t[1],1])[3]+sqrt(2)*sdi([t[1],1])[4]]),[t[1],t[2]]);
#@ square_diffeo_E0_inverse_pattern
square_diffeo_E0_inverse_pattern := (A,t) -> [
A[9]*t[1]^2*t[2]^2+A[6]*t[1]*t[2]^2-t[1]^2*t[2]*A[9]-t[1]^2*t[2]*A[16]+A[3]*t[2]^2+
t[1]*t[2]*A[16]+(1/2)*t[1]*t[2]*sqrt(2)-t[1]*t[2]*A[6]+A[16]*t[1]^2-
(1/2)*sqrt(2)*t[2]-t[2]*A[3]-t[1]*A[16]-(1/2)*sqrt(2)*t[1]+(1/2)*sqrt(2),
A[18]*t[1]^2*t[2]^2+A[15]*t[1]*t[2]^2+A[17]*t[1]^2*t[2]-t[2]^2*A[15]-t[2]^2*A[18]-
t[1]*t[2]*A[15]-t[1]*t[2]*A[18]-t[1]*t[2]-t[1]*t[2]*A[17]+(1/2)*t[1]*t[2]*sqrt(2)+
A[16]*t[1]^2+t[2]*A[15]+t[2]*A[18]+t[2]-(1/2)*sqrt(2)*t[2]-t[1]*A[16]-
(1/2)*sqrt(2)*t[1]+(1/2)*sqrt(2),
A[27]*t[1]^2*t[2]^2+A[24]*t[1]*t[2]^2+A[26]*t[1]^2*t[2]-t[1]*t[2]*A[26]-
t[1]*t[2]*A[27]-t[1]*t[2]*A[24]+(1/3)*sqrt(6)*t[1]*t[2]-t[1]*t[2]-A[26]*t[1]^2-
sqrt(2)*A[35]*t[1]^2-sqrt(2)*A[36]*t[1]^2-A[27]*t[1]^2+sqrt(2)*t[1]*A[36]+
sqrt(2)*t[1]*A[35]+t[1]*A[26]+t[1]*A[27]+t[1],
A[36]*t[1]^2*t[2]^2+A[33]*t[1]*t[2]^2+A[35]*t[1]^2*t[2]-t[1]*t[2]*A[36]-
t[1]*t[2]*A[33]-t[1]*t[2]*A[35]-(1/3)*sqrt(3)*t[1]*t[2]
]:
######################################################################
#@ make_square_diffeo_E0_record
make_square_diffeo_E0_record := proc(x0)
local u,e,n0,u0,v0,t0,tu0,tv0,J0,eqs,sol,x1,P;
n0 := evalf(dg0(x0));
n0 := n0 /~ nm4(n0);
t0 := evalf(square_diffeo_E0(x0));
u0 := [u[1],u[2],u[3],u[4]];
x1 := x0 +~ e *~ u0;
eqs := expand(evalf([rho(x1),g0(x1),op(square_diffeo_E0(x1))]));
eqs := map(coeff,eqs,e,1) -~ [0,0,1,0];
sol := solve(eqs);
u0 := evalf(subs(sol,u0));
u0 := u0 /~ nm4(u0);
v0 := cross_product4(x0,n0,u0);
tu0 := evalf(map(coeff,expand(square_diffeo_E0(x0 +~ e *~ u0)),e,1));
tv0 := evalf(map(coeff,expand(square_diffeo_E0(x0 +~ e *~ v0)),e,1));
J0 := Determinant(Matrix([tu0,tv0]));
P := table();
P["x"] := x0;
P["n"] := n0;
P["u"] := u0;
P["v"] := v0;
P["t"] := t0;
P["tu"] := tu0;
P["tv"] := tv0;
P["J"] := J0;
P["K"] := evalf(curvature0(x0));
P["M"] := evalf(rescale_x(x0));
return(eval(P));
end:
######################################################################
#@ square_diffeo_E0_JM
square_diffeo_E0_JM :=
unapply(Matrix([xx,dg0(xx),seq([seq(diff(square_diffeo_E0(xx)[i],x[j]),j=1..4)],i=1..2)]),x);
#@ square_diffeo_E0_J
square_diffeo_E0_J := unapply(simplify(NF_x0(Determinant(square_diffeo_E0_JM(x)))/nm4(dg0(xx))),x);
#@ square_diffeo_E0_alt_JM
square_diffeo_E0_alt_JM :=
unapply(Matrix([xx,dg0(xx),seq([seq(diff(square_diffeo_E0_alt(xx)[i],x[j]),j=1..4)],i=1..2)]),x);
#@ square_diffeo_E0_alt_J
square_diffeo_E0_alt_J := unapply(simplify((Determinant(square_diffeo_E0_alt_JM(x)))/nm4(dg0(xx))),x);
######################################################################
#@ sd_plot_base
sd_plot_base := display(
polygon([[0,0,0],[1,0,0],[1,1,0],[0,1,0]],colour=grey),
line([0,0,0],[0,1,0],colour=c_colour[0]),
line([0,0,0],[1,0,0],colour=c_colour[1]),
line([0,1,0],[1,1,0],colour=c_colour[3]),
line([1,0,0],[1,1,0],colour=c_colour[5]),
axes=none,scaling=constrained
):
#@ sd_plot
sd_plot := proc(f)
local i,j,SDI,N,P;
require_square_diffeo_E0_inverse():
SDI := eval(square_diffeo_E0_inverse_table);
N := square_diffeo_E0_inverse_order;
P := table():
for i from 0 to N do
for j from 0 to N do
P[i,j] := [i/N,j/N,evalf(eval(subs(x = SDI[i/N,j/N],f)))];
od;
od;
display(
seq(seq(polygon([P[i,j],P[i+1,j],P[i+1,j+1]],style=patchnogrid),i=0..N-1),j=0..N-1),
seq(seq(polygon([P[i,j],P[i,j+1],P[i+1,j+1]],style=patchnogrid),i=0..N-1),j=0..N-1)
);
end: