Skip to content

flatsurf/flatsurf

Repository files navigation

logo

libflatsurf & pyflatsurf

License: GPL 3.0 or later Test Coverage Benchmarks DOI 10.5281/zenodo.4006152

a C++ backend for sage-flatsurf

libflatsurf is C++ library to work with translation surfaces and pyflatsurf is a low-level wrapper to use libflatsurf from Python.

If you came here looking for the flatsurf project, you probably want to start with sage-flatsurf which provides a unified interface to these and many other libraries in the SageMath computer algebra system.

Source tarballs can be downloaded at https://github.com/flatsurf/flatsurf/releases.

This repository contains two related projects:

  • libflatsurf a C++ library
  • pyflatsurf a Python wrapper for libflatsurf

The dependencies are:

Usage

We create a regular hexagon, and glue its opposites sides.

#include <flatsurf/flatsurf.hpp>

using flatsurf::FlatTriangulation;
using R = eantic::renf_elem_class;
using R2 = flatsurf::Vector<R>;

// We create a number field to represent the edges of the hexagon.
auto K = eantic::renf_class::make("x^2 - 3", "x", "1.73 +/- 0.1");
auto x = K->gen();

// The edge vectors of a regular hexagon.
auto vectors = std::vector{R2(R(*K, 2), R(*K, 0)), R2(R(*K, 1), x), R2(R(*K, 3), x), R2(R(*K, 1), -x), R2(R(*K, 4), R(*K, 0)), R2(R(*K, 3), x)};

// The edges are going to be labeled 1,…,6.
// The labels -1,…,-6 refer to the negative of these edges.
// We give the permutation obtained by walking around the two marked vertices
// of the hexagon to specify the edge gluing in our translation surface.
auto vertices = std::vector<std::vector<int>>({{1, 3, -4, -5, -3, -2}, {2, -1, -6, 4, 5, 6}});

auto hexagon = FlatTriangulation(vertices, vectors);

std::cout << hexagon << std::endl;
// FlatTriangulationCombinatorial(vertices = (1, 3, -4, -5, -3, -2)(-1, -6, 4, 5, 6, 2), faces = (1, 2, -3)(-1, -2, 6)(3, -5, 4)(-4, -6, 5)) with vectors {1: (2, 0), 2: (1, (x ~ 1.7320508)), 3: (3, (x ~ 1.7320508)), 4: (1, (-x ~ -1.7320508)), 5: (4, 0), 6: (3, (x ~ 1.7320508))}

We enumerate saddle connections in this hexagon up to length 4.

auto connections = flatsurf::SaddleConnections(hexagon).bound(4);
for (auto c : connections)
    std::cout << c << std::endl;
// 1
// -1
// 2
// (-3, (x ~ 1.7320508)) from 2 to 4
// (0, (2*x ~ 3.4641016)) from 2 to -6
// (-2, (2*x ~ 3.4641016)) from 2 to -2
// -2
// (3, (-x ~ -1.7320508)) from -2 to -4
// (0, (-2*x ~ -3.4641016)) from -2 to 3
// (2, (-2*x ~ -3.4641016)) from -2 to 2
// 3
// (2, (2*x ~ 3.4641016)) from 3 to -6
// (0, (2*x ~ 3.4641016)) from 3 to -2
// -3
// 4
// (3, (-x ~ -1.7320508)) from 4 to 2
// -4
// (-3, (x ~ 1.7320508)) from -4 to -2
// 5
// -5
// 6
// -6
// (-2, (-2*x ~ -3.4641016)) from -6 to 3
// (0, (-2*x ~ -3.4641016)) from -6 to 2

We can perform the same computation with the Python interface (though we recommend you use sage-flatsurf which makes this much easier to accomplish):

>>> import pyflatsurf
>>> import cppyy
>>> import pyeantic

>>> K = pyeantic.eantic.renf_class.make("x^2 - 3", "x", "1.73 +/- 0.1")
>>> x = K.gen()
>>> R2 = pyflatsurf.flatsurf.Vector[cppyy.gbl.eantic.renf_elem_class]
>>> R = pyeantic.eantic.renf_elem
>>> vectors = [R2(R(K, 2), R(K, 0)), R2(R(K, 1), x), R2(R(K, 3), x), R2(R(K, 1), -x), R2(R(K, 4), R(K, 0)), R2(R(K, 3), x)]
>>> vertices = [[1, 3, -4, -5, -3, -2], [2, -1, -6, 4, 5, 6]]
>>> S = pyflatsurf.Surface(vertices, vectors)

>>> C = S.connections().bound(4)
>>> for c in C: print(c)
1
-1
2
(-3, (x ~ 1.7320508)) from 2 to 4
(0, (2*x ~ 3.4641016)) from 2 to -6
(-2, (2*x ~ 3.4641016)) from 2 to -2
-2
(3, (-x ~ -1.7320508)) from -2 to -4
(0, (-2*x ~ -3.4641016)) from -2 to 3
(2, (-2*x ~ -3.4641016)) from -2 to 2
3
(2, (2*x ~ 3.4641016)) from 3 to -6
(0, (2*x ~ 3.4641016)) from 3 to -2
-3
4
(3, (-x ~ -1.7320508)) from 4 to 2
-4
(-3, (x ~ 1.7320508)) from -4 to -2
5
-5
6
-6
(-2, (-2*x ~ -3.4641016)) from -6 to 3
(0, (-2*x ~ -3.4641016)) from -6 to 2

Build and Develop flatsurf with pixi

If you have cloned the source repository, make sure to pull in all the third-party header-only libraries by running:

git submodule update --init

If you are distributing flatsurf or you are a purist who only wants to interact with autotools directly, then you should skip to the next section. Otherwise, we strongly recommend that you install pixi and then use the following commands:

  • pixi run test build flatsurf and run the libflatsurf and pyflatsurf test suites
  • pixi run sage build flatsurf and spawn SageMath with the local libflatsurf and pyflatsurf installed
  • pixi run doc to build and preview the documentation
  • pixi run compile-commands to generate a compile_commands.json that your IDE might be able to use to make sense of this project
What is pixi?

pixi is a tool based on conda & conda-forge for developers so that we can all use the same workflows in the same defined environments.

pixi allows us to ship a very opinionated setup to developers of flatsurf, namely a number of opinionated scripts with corresponding tested (and opinionated) dependencies.

This makes the whole development experience much more reliable and reproducible, e.g., the CI on GitHub Pull Requests runs with the exact same setup, so if something fails there, you can just run the CI command to hopefully get exactly the same behavior locally.

How do I use pixi?

If you have not used pixi before, the most relevant pixi command is:

pixi run TASK

Run pixi task list to see the available tasks.

All tasks are defined in the pixi.toml file and most are used somewhere in our GitHub Continuous Integration setup, see .github/workflows/.

Why don't we add all things to the Makefiles but use pixi tasks?

Packagers do prefer a system that is as minimalistic as possible. Any opinionated bit in the build system, such as setting compiler flags, usually needs to be patched out by software distributions. That's why our Makefiles are trying to follow the autoconfiscated standards as closely as possible. And essentially all that pixi does is to call these Makefiles without you having to figure out how everything works in detail.

Can I use configure & make with pixi?

More experienced developers may not want to use these tasks. You can also just use the curated list of dependencies that pixi provides and drop into a shell with these dependencies installed. For example, to run the libflatsurf test suite directly, you could do:

pixi shell -e dev
./bootstrap
cd libflatsurf
./configure
make check

Note that the following section contains more details about this configure && make workflow that might be of interest to you.

Build from the Source Code Repository or a Tarball

If you have cloned the source directory and you decided not to use pixi, you will need to setup the configure script and Makefile using autotools. That is

git submodule update --init
./bootstrap

If you obtained a tarball of the sources or if the preceding step worked, you can now run

./configure
make
make check  # to run our test suite
make install  # to install into /usr/local

If you happen to have any dependency installed in a non standard directory, you will have to specify the CPPFLAGS and LDFLAGS variables for the configure script

./configure CPPFLAGS=-I/my/path/include LDFLAGS=-L/my/path/lib

For best performance run CXXFLAGS="-O3 -flto -march=native -mtune=native" CXX="g++ -fno-semantic-interposition" ./configure instead of ./configure as this code greatly benefits from flto inlining. (Unfortunately, libtool filters out -fno-semantic-interposition as of early 2019 so we can not pass it as part of CXXFLAGS. If you are using clang, -fno-semantic-interposition does not seem to be necessary.) Do not use -Ofast or -ffast-math as parts of our code rely on IEEE compliance. You might want to add -g3 to CXXFLAGS which does not hurt performance but gives a better debugging experience. For the best debugging experience, you might want to replace -O3 with -Og or even -O0 but the latter results in poor performance.

Additionally, you might want to run configure with --disable-static which improves the build time.

If your compiler supports it, you can try to add -fvisibility=hidden -fvisibility-inlines-hidden to your CXXFLAGS. This hides internal bits in the resulting library which have lead to crashes in the past due to conflicting header-only libraries.

perf works well to profile when you make sure that CXXFLAGS contain -fno-omit-framepointer. You can then for example run our test suite with perf record --call-graph dwarf make check. Apart from perf itself there are several ways to analyze the output, hotspot might be the most convenient one at the time of this writing.

Note that the C++ compiler package from conda disabled all assertions. To enable assertions export CPPFLAGS="$CPPFLAGS -UNDEBUG" before running configure and make.

Feedback and Contributions

If you have tried out flatsurf, we are thrilled to learn about your experiences. If you ran into any problems or have suggestions for improvement, please create an issue.

If you want to contribute to flatsurf, pull requests are always welcome ❤️

We are also happy to walk you through the process personally if you are unsure how to get started. Feel free to reach out in the #flatsurf stream on Zulip in any case.

License

flatsurf is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. See https://www.gnu.org/licenses/.

How to Cite This Project

If you have used this project in the preparation of a publication, please cite it as described on our zenodo site.

Acknowledgements

  • Julian Rüth's contributions to this project have been supported by the Simons Foundation Investigator grant of Alex Eskin.

Maintainers

About

Translation Surfaces in C++/Python

Resources

License

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •