In this vignette, we define some configuration spaces of an even number of points on the circle, and show that they are homeomorphic to real projective spaces \(\mathbb{R}\text{P}^n\). Since \(\mathbb{R}\text{P}^3\) is homeomorphic to the group of 3x3 rotation matrices \(\text{SO(3)}\), we also have a homeomorphism with that space.
A prerequisite to understanding this vignette is the section on spaces of arcs \(A_n\) in the User Guide vignette.
The current vignette is illustrated with some animated GIFS showing paths in the space of 2 or 4 points on the circle. The GIF plots are made with help of the package gifski and this function:
GIFfromrotationlist <- function( rotationlist, index=1L, fps=4, vpsize=c(480,512) )
{
require( 'gifski' )
# make temp folder
pathtemp = tempdir() # "./figs" ; if( ! file.exists(pathtemp) ) dir.create(pathtemp)
count = length( rotationlist )
namevec = names( rotationlist )
for( k in 1:count )
{
filename = sprintf( "%s/plot%03d.png", pathtemp, k )
png( filename=filename, width=vpsize[1], height=vpsize[2], units = "px" )
rotation3x3 = rotationlist[[k]]
arcmat = arcsfromrotation( rotation3x3, tol=1.e-7 )
plotarcs( arcmat, labels=FALSE, main=namevec[k], lwd=NA, cex=3, col='blue' )
rect( -0.83, -0.4, 0.83, 0.4, col='white', border='black' )
matlabel = sprintf( "%+.4f", rotation3x3 )
matlabel = gsub( '[+]', ' ', matlabel )
dim(matlabel) = c(3,3)
matlabel = capture.output( print(matlabel,quote=FALSE) )
matlabel = matlabel[-1] # ignore the column labels
matlabel = substr( matlabel, 5, 1000 ) # ignore the row labels
text( 0, c(0.3,0,-0.3), matlabel, adj=c(0.51,0.5), cex=1.5, family='mono' )
dev.off()
}
pathvec = dir( pathtemp, pattern="png$", full=T )
gif_file = sprintf( "%s/animation%g.gif", pathtemp, index )
out = gifski( pathvec, gif_file=gif_file, delay=1/fps, progress=F, width=vpsize[1], height=vpsize[2] )
res = file.remove( pathvec ) # cleanup the .PNG files, leaving just the .GIF
return(out)
}
The sphere \(\mathbb{S}^{2n}\) has natural involution, the antipodal map, given by \(\alpha(u) = -u\).
The space of arcs \(A_n\) has a natural involution \(\gamma\), which is the complementation operation, given by \(\gamma(V) = \operatorname{Cl}(\mathbb{S}^1 - V)\). The closure \(\operatorname{Cl}\) is only necessary to create closed arcs. Note that \(\gamma()\) has the important property that it leaves the arc endpoints fixed.
It is easy to show that the homeomorphism \(A_n ~ \longleftrightarrow ~ \mathbb{S}^{2n}\) conjugates these 2 involutions. We have a commutative diagram:
the involutions are conjugate
If we identify pairs of points for both spaces with the equivalence relation \(\sim\), we get an induced homeomorphism \(A_n/\sim ~ \longleftrightarrow ~ \mathbb{S}^{2n}/\sim\). The latter space is real projective space \(\mathbb{R}\text{P}^{2n}\). Since \(\gamma\) leaves the arc endpoints fixed, we can view a point in \(A_n/\sim\) as simply the endpoints of the arcs; this is justified in the next section.
We define \(P_{2n}\) to be the configuration space of \(2n\) or fewer and even number of points in the circle \(\mathbb{S}^1\). So \(P_2\) is the space of 2 points, \(P_4\) is the space of 4 or 2 points, etc. We also define \(P_0\) to be a single point. We have proper inclusions: \[\begin{equation} P_0 ~ \subset ~ P_2 ~ \subset ~ P_4 ~ \subset ~ P_6 ~ \subset ~ ... \end{equation}\] Given \(2n\) distinct points in the circle, there are 2 sets of \(n\) arcs that have these as endpoints. These 2 sets are complements of each other, which are identified under the above equivalence relation. Therefore \(P_{2n}\) and \(A_n / \sim\) are bijective as sets. We take the induced topology on \(A_n / \sim\) and transfer it to \(P_{2n}\). The important thing is that if 2 neighboring points of a configuration in \(P_{2n}\) get close to each other, in the limit the point configuration converges to a configuration in \(P_{2(n-1)}\) where the 2 points of the configuration “disappear”. Depending on how the arcs are selected, either the arc between the points shrinks to nothing, or the gap between two arcs shrinks to nothing and the two arcs are combined. In either case the number of arcs is reduced by 1. We saw in the previous section that there is a homeomorphism \(A_n / \sim ~ \longleftrightarrow ~ \mathbb{R}\text{P}^{2n}\), and so there is a homeomorphism: \[\begin{equation} P_{2n} ~ \longleftrightarrow ~ \mathbb{R}\text{P}^{2n} \end{equation}\]
SIDE NOTE: In particular we have \(P_2 ~ \leftrightarrow ~ \mathbb{R}\text{P}^2\). There is another configuration space of 2 points on the circle which is the cartesian product of two copies modulo the permutation of the points: \((\mathbb{S}^1 \times \mathbb{S}^1) / \sim\). This is given the quotient topology, so as 2 points converge to each other they become a single point. This configuration space is a Möebius band, with boundary being those single points. If the boundary is collapsed to a point, we get \(P_2 ~ \leftrightarrow ~ \mathbb{R}\text{P}^2\).
What about odd dimensions ? It turns out we can add a constraint that makes an interesting homeomorphism. Call a configuration of \(n\) arcs balanced if and only they have total length \(\pi\). Note that if a configuration is balanced then its complement under \(\gamma\) is also balanced. Denote the subspace of balanced arc configurations by \(A_n^\pi \subset A_n\). Viewed as points in \(\partial Z_n ~ \leftrightarrow ~ \mathbb{S}^{2n}\) this corresponds to intersecting the boundary of \(Z_n\) with the hyperplane \(L = \pi\). The intersection is a sphere of one lower dimension: \(\mathbb{S}^{2n-1}\). Similarly, call a configuration of \(2n\) points balanced if and only if the generated arcs are balanced. There are 2 ways to choose these arcs, but if one way has total length \(\pi\) then so does the other. Denote the subspace of balanced point configurations by \(P^\pi_{2n} \subset P_{2n}\). We have homeomorphisms \[\begin{equation} A_n^\pi ~ \longleftrightarrow ~ \mathbb{S}^{2n-1} \hspace{20pt} \text{and} \hspace{20pt} P_{2n}^\pi ~ \longleftrightarrow ~ \mathbb{R}\text{P}^{2n-1} \end{equation}\] In particular when \(n=2\) we have \[\begin{equation} P_{4}^\pi ~ \longleftrightarrow ~ \mathbb{R}\text{P}^{3} ~ \longleftrightarrow ~ \text{SO(3)} \end{equation}\] The second homeomorphism is well-known and is defined using the standard mapping from unit quaternions to 3x3 rotation matrices. In the following animations we generate a loop of rotations around a fixed axis, map the 3x3 rotation matrices to balanced configurations of 4 or 2 points in the circle, and plot them. The loop of rotations are generated with this function:
circleofrotations <- function( axis, count=72+1 )
{
out = vector( count, mode='list' )
namevec = character( count )
for( i in 1:count )
{
theta_deg = 360 * (i-1)/(count-1)
theta = pi/180 * theta_deg # theta is in radians, starting at 0
out[[i]] = rotationaroundaxis( axis, theta )
namevec[i] = sprintf( "rotation around axis [%g,%g,%g]\ntheta=%g deg",
axis[1], axis[2], axis[3], theta_deg )
}
names(out) = namevec
return( out )
}
SIDE NOTE: The above-mentioned configuration space for 3 points, using the quotient topology on \(\mathbb{S}^1 {\times} \mathbb{S}^1 {\times} \mathbb{S}^1\), was shown to be homemorphic to \(\mathbb{S}^3\) in [1].
This animation start at the trivial identity matrix, which maps to the antipodal points \((0,\pm1)\). Then a circle of rotations around [0,0,1] are generated which return back to the identity again. The corresponding balanced configuration of points on the circle are plotted in blue.
circle = circleofrotations( c(0,0,1), count=72+1 )
gif_file = GIFfromrotationlist( circle, index=1, vpsize=c(480,480) )
This animation start at the trivial identity matrix, and then a circle of rotations around [0,1,0] are generated which return back to the identity again. The corresponding balanced configuration of points on the circle are plotted in blue.
circle = circleofrotations( c(0,1,0), count=72+1 )
gif_file = GIFfromrotationlist( circle, index=2, vpsize=c(480,480) )
This animation start at the trivial identity matrix, and then a circle of rotations around [1,0,0] are generated which return back to the identity again. The corresponding balanced configuration of points on the circle are plotted in blue.
circle = circleofrotations( c(1,0,0), count=72+1 )
gif_file = GIFfromrotationlist( circle, index=3, vpsize=c(480,480) )
This case is different. There are only 2 antipodal points, and all these balanced point configurations are in \(P_2^\pi \subset P_4^\pi\).
This animation start at the trivial identity matrix, and then a random axis is generated, and then a loop of rotations around that axis is generated which return back to the identity again. The corresponding balanced configuration of points on the circle are plotted in blue.
set.seed(0)
axis = rnorm(3)
axis = axis / sqrt( sum(axis^2) )
circle = circleofrotations( axis, count=72+1 )
gif_file = GIFfromrotationlist( circle, index=4, vpsize=c(480,480) )
R version 4.5.0 (2025-04-11 ucrt) Platform: x86_64-w64-mingw32/x64 Running under: Windows 11 x64 (build 26100) Matrix products: default LAPACK version 3.12.1 locale: [1] LC_COLLATE=C [2] LC_CTYPE=English_United States.utf8 [3] LC_MONETARY=English_United States.utf8 [4] LC_NUMERIC=C [5] LC_TIME=English_United States.utf8 time zone: America/Los_Angeles tzcode source: internal attached base packages: [1] stats graphics grDevices utils datasets methods base other attached packages: [1] zonohedra_0.4-0 rgl_1.3.18 gifski_1.32.0-2 flextable_0.9.7 [5] polarzonoid_0.1-2 loaded via a namespace (and not attached): [1] katex_1.5.0 jsonlite_2.0.0 qpdf_1.3.5 [4] compiler_4.5.0 pdftools_3.5.0 equatags_0.2.1 [7] tinytex_0.57 Rcpp_1.0.14 zip_2.3.3 [10] xml2_1.3.8 magick_2.8.6 jquerylib_0.1.4 [13] fontquiver_0.2.1 systemfonts_1.2.3 textshaping_1.0.1 [16] uuid_1.2-1 yaml_2.3.10 fastmap_1.2.0 [19] R6_2.6.1 microbenchmark_1.5.0 gdtools_0.4.2 [22] curl_6.2.2 knitr_1.50 htmlwidgets_1.6.4 [25] logger_0.4.0 openssl_2.3.2 bslib_0.9.0 [28] rlang_1.1.6 V8_6.0.3 cachem_1.1.0 [31] xfun_0.52 sass_0.4.10 cli_3.6.5 [34] magrittr_2.0.3 digest_0.6.37 grid_4.5.0 [37] base64enc_0.1-3 askpass_1.2.1 lifecycle_1.0.4 [40] evaluate_1.0.3 glue_1.8.0 data.table_1.17.2 [43] fontLiberation_0.1.0 officer_0.6.8 ragg_1.4.0 [46] xslt_1.5.1 fontBitstreamVera_0.1.1 rmarkdown_2.29 [49] tools_4.5.0 htmltools_0.5.8.1