├── csharp
├── test
│ ├── Usings.cs
│ ├── test.csproj
│ ├── SubspanTest.cs
│ └── MiniballTest.cs
├── miniball
│ ├── miniball.csproj
│ ├── highdim
│ │ ├── Logging.cs
│ │ ├── Quality.cs
│ │ └── Miniball.cs
│ └── model
│ │ ├── PointSet.cs
│ │ ├── ArrayPointSet.cs
│ │ └── PointSetUtils.cs
├── example
│ ├── example.csproj
│ └── Program.cs
└── src.sln
├── cpp
├── test
│ ├── .gitignore
│ └── example.C
└── main
│ ├── Seb_point.h
│ ├── Seb_debug.h
│ ├── Seb_debug.C
│ ├── Seb_configure.h
│ ├── Seb.h
│ ├── Subspan.h
│ ├── Subspan-inl.h
│ └── Seb-inl.h
├── material
├── seb.pdf
└── old
│ ├── rankplot.gnp
│ ├── TODO
│ ├── gensuit.pl
│ ├── run_cplex.C
│ └── pts2mps.C
├── python
├── .gitignore
├── setup.py
├── miniball
│ └── __init__.py
├── pyproject.toml
├── test
│ └── test_miniball.py
├── miniball_python.cpp
└── CMakeLists.txt
├── .gitignore
├── java
├── src
│ ├── test
│ │ ├── resources
│ │ │ └── com
│ │ │ │ └── dreizak
│ │ │ │ └── miniball
│ │ │ │ └── highdim
│ │ │ │ └── data
│ │ │ │ ├── simplex_10.data
│ │ │ │ └── simplex_15.data
│ │ └── java
│ │ │ └── com
│ │ │ └── dreizak
│ │ │ └── miniball
│ │ │ └── highdim
│ │ │ ├── SubspanTest.java
│ │ │ └── MiniballTest.java
│ └── main
│ │ └── java
│ │ └── com
│ │ └── dreizak
│ │ └── miniball
│ │ ├── highdim
│ │ ├── Logging.java
│ │ ├── Quality.java
│ │ ├── Miniball.java
│ │ └── Subspan.java
│ │ └── model
│ │ ├── PointSet.java
│ │ ├── ArrayPointSet.java
│ │ └── PointSetUtils.java
├── Readme.text
└── pom.xml
├── .pre-commit-config.yaml
└── README.md
/csharp/test/Usings.cs:
--------------------------------------------------------------------------------
1 | global using Xunit;
--------------------------------------------------------------------------------
/cpp/test/.gitignore:
--------------------------------------------------------------------------------
1 | example
2 | times.png
3 | boost*
4 |
--------------------------------------------------------------------------------
/material/seb.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hbf/miniball/HEAD/material/seb.pdf
--------------------------------------------------------------------------------
/python/.gitignore:
--------------------------------------------------------------------------------
1 | miniball_python.so
2 | test.cpp
3 | test.py
4 | __pycache__
5 | dist/
6 | build/
7 | *.egg-info
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *~
3 | .settings
4 | .project
5 | .classpath
6 | java/target
7 | benchmark/data/*.data
8 | bin
9 | obj
10 | .vscode
--------------------------------------------------------------------------------
/python/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | print("Setuptools installation is deprecated - please use `pip install .`")
4 | setup()
5 |
--------------------------------------------------------------------------------
/java/src/test/resources/com/dreizak/miniball/highdim/data/simplex_10.data:
--------------------------------------------------------------------------------
1 | 10 10
2 | 1 0 0 0 0 0 0 0 0 0
3 | 0 1 0 0 0 0 0 0 0 0
4 | 0 0 1 0 0 0 0 0 0 0
5 | 0 0 0 1 0 0 0 0 0 0
6 | 0 0 0 0 1 0 0 0 0 0
7 | 0 0 0 0 0 1 0 0 0 0
8 | 0 0 0 0 0 0 1 0 0 0
9 | 0 0 0 0 0 0 0 1 0 0
10 | 0 0 0 0 0 0 0 0 1 0
11 | 0 0 0 0 0 0 0 0 0 1
12 |
--------------------------------------------------------------------------------
/csharp/miniball/miniball.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 | true
8 |
9 |
10 |
--------------------------------------------------------------------------------
/material/old/rankplot.gnp:
--------------------------------------------------------------------------------
1 | # rankplot.gnp
2 | # 2003, by Martin Kutz
3 | # plot rank data from data file "rank.log into "ranks.ps"
4 |
5 | set title "Rank Statistics"
6 | set xlabel "iteration"
7 | set ylabel "rank"
8 | set autoscale
9 | # set border 3
10 | set terminal postscript
11 | set output "ranks.ps"
12 | plot "ranks.log" notitle with lines
13 |
--------------------------------------------------------------------------------
/csharp/example/example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Exe
9 | net7.0
10 | enable
11 | enable
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
3 | rev: v3.1.0
4 | hooks:
5 | - id: check-yaml
6 | - id: end-of-file-fixer
7 | - id: trailing-whitespace
8 | - repo: https://github.com/astral-sh/ruff-pre-commit
9 | rev: v0.12.9
10 | hooks:
11 | - id: ruff
12 | types_or: [ python ]
13 | args: [ --fix ]
14 | - id: ruff-format
15 | types_or: [ python]
16 |
--------------------------------------------------------------------------------
/material/old/TODO:
--------------------------------------------------------------------------------
1 | Questions:
2 | - Do we need size in Affine_sub_span?
3 | - Should Affine_sub_span::clear() intialize to Q={p} instead of Q={}?
4 | - Is it a good idea to update the radius after walking by computing the
5 | distance from the new center to the stopping point? (We do this now
6 | because we don't "know" the index of a ball in Q right now...)
7 |
8 | Possible optimization:
9 | - Implement class Point with C-arrays instead of vectors -- I guess
10 | this doesn't help anything at all.
11 |
--------------------------------------------------------------------------------
/python/miniball/__init__.py:
--------------------------------------------------------------------------------
1 | from ._miniball import _compute_miniball
2 |
3 | import numpy as np
4 |
5 | __all__ = ["miniball"]
6 |
7 |
8 | def miniball(points: np.typing.ArrayLike):
9 | """Compute the smallest enclosing ball for a set of points."""
10 |
11 | points = np.ascontiguousarray(points, dtype=np.float64)
12 |
13 | if len(points.shape) != 2:
14 | msg = f"Input array must be 2-dimensional! Got shape `{points.shape}`."
15 | raise TypeError(msg)
16 | return _compute_miniball(points)
17 |
--------------------------------------------------------------------------------
/java/src/test/resources/com/dreizak/miniball/highdim/data/simplex_15.data:
--------------------------------------------------------------------------------
1 | 15 15
2 | 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3 | 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
4 | 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
5 | 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
6 | 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
7 | 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
8 | 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
9 | 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
10 | 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
11 | 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
12 | 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
13 | 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
14 | 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
15 | 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
16 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
17 |
--------------------------------------------------------------------------------
/java/src/main/java/com/dreizak/miniball/highdim/Logging.java:
--------------------------------------------------------------------------------
1 | package com.dreizak.miniball.highdim;
2 |
3 | /**
4 | * A very simple logging class used for debugging.
5 | */
6 | class Logging
7 | {
8 | final static boolean log = false;
9 |
10 | public final static void warn(String msg)
11 | {
12 | if (log) System.err.println("[warn] " + msg);
13 | }
14 |
15 | public final static void info(String msg)
16 | {
17 | if (log) System.err.println("[info] " + msg);
18 | }
19 |
20 | public final static void debug(String msg)
21 | {
22 | if (log) System.err.println("[debug] " + msg);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/csharp/miniball/highdim/Logging.cs:
--------------------------------------------------------------------------------
1 | namespace SEB;
2 |
3 | ///
4 | /// A very simple logging class used for debugging.
5 | ///
6 | static class Logging
7 | {
8 |
9 | public static bool log = false;
10 |
11 | public static void Warn(string msg)
12 | {
13 | if (log) System.Console.WriteLine($"[warn] {msg}");
14 | }
15 |
16 | public static void Info(string msg)
17 | {
18 | if (log) System.Console.WriteLine($"[info] {msg}");
19 | }
20 |
21 | public static void Debug(string msg)
22 | {
23 | if (log) System.Console.WriteLine($"[debug] {msg}");
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/python/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["scikit-build-core>=0.10", "nanobind>=1.3.2", "numpy"]
3 | build-backend = "scikit_build_core.build"
4 |
5 | [project]
6 | name = "miniball"
7 | version = "2.0.0"
8 | description = "Library to find the smallest enclosing ball of points."
9 | readme = "../README.md"
10 | requires-python = ">=3.8"
11 | authors = [
12 | { name = "Kaspar Fischer" },
13 | { name = "Bernd Gärtner" },
14 | { name = "Martin Kutz" },
15 | ]
16 |
17 | dependencies = [
18 | "numpy",
19 | "nanobind",
20 | ]
21 |
22 | [project.optional-dependencies]
23 | test = ["pytest"]
24 |
25 | [project.urls]
26 | Source = "https://github.com/hbf/miniball"
27 | Issues = "https://github.com/hbf/miniball/issues"
28 |
29 | [tool.scikit-build]
30 | build.verbose = true
31 | minimum-version = "build-system.requires"
32 | build-dir = "build/{wheel_tag}"
33 | wheel.py-api = "cp312"
34 |
--------------------------------------------------------------------------------
/csharp/test/test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 | runtime; build; native; contentfiles; analyzers; buildtransitive
16 | all
17 |
18 |
19 | runtime; build; native; contentfiles; analyzers; buildtransitive
20 | all
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/java/Readme.text:
--------------------------------------------------------------------------------
1 | Deployment instructions
2 | =======================
3 |
4 | The Java project has been setup following the instructions from
5 |
6 | http://stackoverflow.com/questions/14013644/hosting-a-maven-repository-on-github/14013645#14013645
7 |
8 | In order to use it, ensure that your ~/.m2/settings.xml contains your Github login credentials:
9 |
10 |
11 | github
12 | hbf
13 | PASSWORD
14 |
15 |
16 | Then use
17 |
18 | mvn clean deploy
19 |
20 | to create the Maven site, store it in the gh-pages branch of the Github project (accessible at http://hbf.github.com/miniball) and store the JAR file in
21 |
22 | https://raw.github.com/hbf/miniball/mvn-repo/
23 |
24 | After this, any Maven project that uses the repository
25 |
26 |
27 | miniball
28 | https://raw.github.com/hbf/miniball/mvn-repo/
29 |
30 | true
31 | always
32 |
33 |
34 |
35 | will be able to download the JAR.
--------------------------------------------------------------------------------
/python/test/test_miniball.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from miniball import miniball
3 | import numpy as np
4 |
5 |
6 | def test_package():
7 | from miniball import miniball
8 |
9 | assert miniball.__doc__ is not None and (
10 | "Compute the smallest enclosing ball for a set of points." in miniball.__doc__
11 | )
12 |
13 |
14 | def test_empty_vector():
15 | with pytest.raises(TypeError, match="Input array must be 2-dimensional"):
16 | miniball(None)
17 |
18 |
19 | def test_identical_points():
20 | point = [3.0, 1.0, 0.0]
21 | test_vector = np.array([point, point], dtype=np.double)
22 | res = miniball(test_vector)
23 | np.testing.assert_array_equal(res["center"], point)
24 | assert res["radius"] == 0
25 | assert res["radius_squared"] == 0
26 |
27 |
28 | def test_two_points():
29 | test_vector = np.array([[3.0, 1.0], [3.0, 1.0], [1.0, 0.0]], dtype=np.double)
30 | res = miniball(test_vector)
31 | np.testing.assert_allclose(res["center"], [2.0, 0.5])
32 | assert res["radius_squared"] == 1.25
33 |
34 |
35 | def test_three_points():
36 | test_vector = [[0, 1], [1, 0], [1, 1]]
37 | res = miniball(test_vector)
38 | np.testing.assert_allclose(res["center"], [0.5, 0.5])
39 | assert res["radius_squared"] == 0.5
40 |
--------------------------------------------------------------------------------
/material/old/gensuit.pl:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/perl
2 |
3 | # gensuit.pl
4 | #
5 | # Martin Kutz
6 | # Kaspar Fischer
7 | #
8 | # Mar. 2003
9 |
10 |
11 | print "========================================\n";
12 | print "Test Suit Generator\n";
13 | print "========================================\n";
14 |
15 |
16 | # parse command line
17 | ($directory,$method,$nlist,$dlist) = @ARGV;
18 |
19 | die "usage: $0 directory method numbers dimensions\n"
20 | unless $directory and $method and $nlist and $dlist;
21 |
22 | # mkdir
23 | $directory .= "/" unless $directory =~ /\/$/;
24 | die "Error: cannot create directory $directory\n"
25 | unless -d $directory or mkdir $directory, oct 777;
26 |
27 | @N = split /\,/, $nlist;
28 | @D = split /\,/, $dlist;
29 |
30 | $" = ", ";
31 | print "n = @N\n";
32 | print "d = @D\n";
33 | print "method: $method\n";
34 | print "directory: $directory\n";
35 |
36 | # underscore method
37 | $_method = $method;
38 | $_method =~ s/\s+/_/g;
39 |
40 | for $d (@D) {
41 | for $n (@N) {
42 | $file = $directory.$_method."_".$n."_".$d.".pts";
43 | print "creating $file.gz\n";
44 | open (GEN,"./gen_random $n $d $method |")
45 | or die "Failed.\n";
46 | open (OUT,">$file")
47 | or die "Failed.\n";
48 | while () {
49 | die $_ if /error/i;
50 | print OUT;
51 | }
52 | close GEN;
53 | close OUT;
54 |
55 | system (gzip,"-f",$file)
56 | and die "Error: zipping failed\n";
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/csharp/miniball/model/PointSet.cs:
--------------------------------------------------------------------------------
1 | namespace SEB;
2 |
3 | ///
4 | /// Abstraction to access the points and their Euclidean coordinates of a set of n points.
5 | /// Classes like {@link Miniball} do not take their input point set as a Java {@link List} are
6 | /// similar data structure, as this forces the user to provide the points in a certain format.
7 | /// Instead, the algorithms require an {@link PointSet} that allows the necessary characteristics of
8 | /// the points to be queried.
9 | ///
10 | /// Notice that most algorithms that use {@link PointSet}s will assume that the underlying point set
11 | /// is immutable.
12 | ///
13 | /// For optimal performance, you may want to copy your points to a Java array and use a ArrayPointSet.
14 | ///
15 | public interface PointSet
16 | {
17 | ///
18 | /// Number of points.
19 | ///
20 | /// the number of points in the point set.
21 | int Size { get; }
22 |
23 | ///
24 | /// The dimension of the ambient space of the points.
25 | ///
26 | /// Each point has dimension() many Euclidean coordinates.
27 | ///
28 | /// the dimension of the ambient space
29 | int Dimension { get; }
30 |
31 | ///
32 | /// The jth Euclidean coordinate of the ith point.
33 | ///
34 | /// the number of the point, 0 ≤ i < size()
35 | /// the dimension of the coordinate of interest, 0 ≤ j ≤ dimension()
36 | /// the jth Euclidean coordinate of the ith point
37 | double Coord(int i, int j);
38 | }
39 |
--------------------------------------------------------------------------------
/java/src/main/java/com/dreizak/miniball/model/PointSet.java:
--------------------------------------------------------------------------------
1 | package com.dreizak.miniball.model;
2 |
3 | import java.util.List;
4 |
5 | import com.dreizak.miniball.highdim.Miniball;
6 |
7 | /**
8 | * Abstraction to access the points and their Euclidean coordinates of a set of n points.
9 | *
10 | * Classes like {@link Miniball} do not take their input point set as a Java {@link List} are
11 | * similar data structure, as this forces the user to provide the points in a certain format.
12 | * Instead, the algorithms require an {@link PointSet} that allows the necessary characteristics of
13 | * the points to be queried.
14 | *
15 | * Notice that most algorithms that use {@link PointSet}s will assume that the underlying point set
16 | * is immutable.
17 | *
18 | * For optimal performance, you may want to copy your points to a Java array and use a
19 | * {@link ArrayPointSet}.
20 | *
21 | * @see ArrayPointSet
22 | */
23 | public interface PointSet
24 | {
25 | /**
26 | * Number of points.
27 | *
28 | * @return the number of points in the point set.
29 | */
30 | int size();
31 |
32 | /**
33 | * The dimension of the ambient space of the points.
34 | *
35 | * Each point has {@code dimension()} many Euclidean coordinates.
36 | *
37 | * @return the dimension of the ambient space
38 | */
39 | int dimension();
40 |
41 | /**
42 | * The jth Euclidean coordinate of the ith point.
43 | *
44 | * @param i
45 | * the number of the point, 0 ≤ i < {@code size()}
46 | * @param j
47 | * the dimension of the coordinate of interest, 0 ≤ j ≤ {@code dimension()}
48 | * @return the jth Euclidean coordinate of the ith point
49 | */
50 | double coord(int i, int j);
51 | }
52 |
--------------------------------------------------------------------------------
/cpp/main/Seb_point.h:
--------------------------------------------------------------------------------
1 | // Synopsis: Simple point class
2 | //
3 | // Authors: Martin Kutz ,
4 | // Kaspar Fischer
5 |
6 | #ifndef SEB_POINT_H
7 | #define SEB_POINT_H
8 |
9 | #include
10 | #include "Seb_configure.h"
11 |
12 | namespace SEB_NAMESPACE {
13 |
14 | template
15 | class Point
16 | // A simple class representing a d-dimensional point.
17 | {
18 | public: // types:
19 | typedef typename std::vector::const_iterator Const_iterator;
20 | typedef typename std::vector::iterator Iterator;
21 |
22 | public: // construction and destruction:
23 |
24 | Point(int d)
25 | // Constructs a d-dimensional point with undefined coordinates.
26 | : c(d)
27 | {
28 | }
29 |
30 | template
31 | Point(int d,InputIterator first)
32 | // Constructs a d-dimensional point with Cartesian center
33 | // coordinates [first,first+d).
34 | : c(first,first+d)
35 | {
36 | }
37 |
38 | public: // access:
39 |
40 | const Float& operator[](unsigned int i) const
41 | // Returns a const-reference to the i-th coordinate.
42 | {
43 | SEB_ASSERT(0 <= i && i < c.size());
44 | return c[i];
45 | }
46 |
47 | Float& operator[](unsigned int i)
48 | // Returns a reference to the i-th coordinate.
49 | {
50 | SEB_ASSERT(0 <= i && i < c.size());
51 | return c[i];
52 | }
53 |
54 | Const_iterator begin() const
55 | // Returns a const-iterator to the first of the d Cartesian coordinates.
56 | {
57 | return c.begin();
58 | }
59 |
60 | Const_iterator end() const
61 | // Returns the past-the-end iterator corresponding to begin().
62 | {
63 | return c.end();
64 | }
65 |
66 | private: // member fields:
67 | std::vector c; // Cartesian center coordinates
68 | };
69 |
70 | } // namespace SEB_NAMESPACE
71 |
72 | #endif // SEB_POINT_H
73 |
--------------------------------------------------------------------------------
/csharp/src.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31903.59
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "miniball", "miniball\miniball.csproj", "{CB239AF9-E1CE-4A42-BF81-1363AC9D270A}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj", "{74EFD69E-315B-41F0-ACCC-AA604FE70977}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example", "example\example.csproj", "{0C74CFB6-21B8-4A7E-B644-B14BEDBD169B}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {CB239AF9-E1CE-4A42-BF81-1363AC9D270A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {CB239AF9-E1CE-4A42-BF81-1363AC9D270A}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {CB239AF9-E1CE-4A42-BF81-1363AC9D270A}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {CB239AF9-E1CE-4A42-BF81-1363AC9D270A}.Release|Any CPU.Build.0 = Release|Any CPU
25 | {74EFD69E-315B-41F0-ACCC-AA604FE70977}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {74EFD69E-315B-41F0-ACCC-AA604FE70977}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {74EFD69E-315B-41F0-ACCC-AA604FE70977}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {74EFD69E-315B-41F0-ACCC-AA604FE70977}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {0C74CFB6-21B8-4A7E-B644-B14BEDBD169B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {0C74CFB6-21B8-4A7E-B644-B14BEDBD169B}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {0C74CFB6-21B8-4A7E-B644-B14BEDBD169B}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {0C74CFB6-21B8-4A7E-B644-B14BEDBD169B}.Release|Any CPU.Build.0 = Release|Any CPU
33 | EndGlobalSection
34 | EndGlobal
35 |
--------------------------------------------------------------------------------
/java/src/main/java/com/dreizak/miniball/model/ArrayPointSet.java:
--------------------------------------------------------------------------------
1 | package com.dreizak.miniball.model;
2 |
3 | /**
4 | * A {@link PointSet} that stores nd-dimensional points in a Java array of
5 | * {@code double}s.
6 | */
7 | public final class ArrayPointSet implements PointSet
8 | {
9 | private int d, n;
10 | private double[] c;
11 |
12 | /**
13 | * Creates an array-based point set to store nd-dimensional points.
14 | *
15 | * @param d
16 | * the dimensions of the ambient space
17 | * @param n
18 | * the number of points
19 | */
20 | public ArrayPointSet(int d, int n)
21 | {
22 | this.d = d;
23 | this.n = n;
24 | this.c = new double[n * d];
25 | }
26 |
27 | @Override
28 | public int size()
29 | {
30 | return n;
31 | }
32 |
33 | @Override
34 | public int dimension()
35 | {
36 | return d;
37 | }
38 |
39 | @Override
40 | public double coord(int i, int j)
41 | {
42 | assert 0 <= i && i < n;
43 | assert 0 <= j && j < d;
44 | return c[i * d + j];
45 | }
46 |
47 | /**
48 | * Sets the jth Euclidean coordinate of the ith point to the given value.
49 | *
50 | * @param i
51 | * the number of the point, 0 ≤ i < {@code size()}
52 | * @param j
53 | * the dimension of the coordinate of interest, 0 ≤ j ≤ {@code dimension()}
54 | * @param v
55 | * the value to set as the jth Euclidean coordinate of the ith point
56 | */
57 | public void set(int i, int j, double v)
58 | {
59 | assert 0 <= i && i < n;
60 | assert 0 <= j && j < d;
61 | c[i * d + j] = v;
62 | }
63 |
64 | public String toString()
65 | {
66 | StringBuffer s = new StringBuffer("{");
67 | for (int i = 0; i < n; ++i)
68 | {
69 | s.append('[');
70 | for (int j = 0; j < d; ++j)
71 | {
72 | s.append(coord(i, j));
73 | if (j < d - 1) s.append(",");
74 | }
75 | s.append(']');
76 | if (i < n - 1) s.append(", ");
77 | }
78 | s.append('}');
79 | return s.toString();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/python/miniball_python.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Synopsis: A binder for enabling this package using numpy arrays.
3 |
4 | Original author: Filip Cornell
5 | Modified by: Adam Heins
6 | Modified by: Jenna Bradley
7 |
8 | */
9 | #include "../cpp/main/Seb.h"
10 | #include
11 | #include
12 |
13 | namespace nb = nanobind;
14 |
15 | using Point = Seb::Point;
16 | using Miniball = Seb::Smallest_enclosing_ball;
17 |
18 | /**
19 | * @brief Computes the smallest enclosing ball for a set of points.
20 | *
21 | * This function takes a 2D NumPy array of points and returns a dictionary
22 | * containing the center, radius, and squared radius of the enclosing ball.
23 | *
24 | * @param points_arr A 2D, C-contiguous NumPy array of dtype float64,
25 | * where each row represents a point.
26 | * @return A dictionary with keys "center" (np.ndarray), "radius" (float),
27 | * and "radius_squared" (float).
28 | */
29 | nb::dict compute_miniball(
30 | nb::ndarray, nb::c_contig> points_arr) {
31 | size_t n_points = points_arr.shape(0);
32 | size_t dim = points_arr.shape(1);
33 |
34 | const double *data = points_arr.data();
35 |
36 | // Create a vector of Point objects
37 | std::vector points;
38 | points.reserve(n_points);
39 | for (size_t i = 0; i < n_points; ++i) {
40 | // Pass a pointer to the beginning of the i-th row.
41 | points.emplace_back(dim, data + i * dim);
42 | }
43 |
44 | // Compute the smallest enclosing ball.
45 | Miniball mb(dim, points);
46 |
47 | nb::dict result;
48 | result["center"] =
49 | nb::ndarray(mb.center_begin(), {dim}).cast();
50 | result["radius"] = mb.radius();
51 | result["radius_squared"] = mb.squared_radius();
52 |
53 | return result;
54 | }
55 |
56 | // Define the Python module using the NB_MODULE macro.
57 | // This replaces all the PyMethodDef, PyModuleDef, and PyInit boilerplate.
58 | NB_MODULE(_miniball, m) {
59 | m.def("_compute_miniball", &compute_miniball, nb::arg("points"),
60 | "Compute the smallest enclosing ball for a set of points.");
61 | }
62 |
--------------------------------------------------------------------------------
/csharp/miniball/model/ArrayPointSet.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using System.Text;
3 |
4 | namespace SEB;
5 |
6 | ///
7 | /// A PointSet that stores nd-dimensional points in a Java array of s
8 | ///
9 | public class ArrayPointSet : PointSet
10 | {
11 |
12 | int d, n;
13 | double[] c;
14 |
15 | ///
16 | /// Creates an array-based point set to store nd-dimensional points.
17 | ///
18 | /// the dimensions of the ambient space
19 | /// the number of points
20 | public ArrayPointSet(int d, int n)
21 | {
22 | this.d = d;
23 | this.n = n;
24 | this.c = new double[n * d];
25 | }
26 |
27 | public int Size => n;
28 |
29 | public int Dimension => d;
30 |
31 | public double Coord(int i, int j)
32 | {
33 | Trace.Assert(0 <= i && i < n);
34 | Trace.Assert(0 <= j && j < d);
35 | return c[i * d + j];
36 | }
37 |
38 | ///
39 | /// Sets the jth Euclidean coordinate of the ith point to the given value.
40 | ///
41 | /// the number of the point, 0 ≤ i < size()
42 | /// the dimension of the coordinate of interest, 0 ≤ j ≤ dimension()
43 | /// the value to set as the jth Euclidean coordinate of the ith point
44 | public void Set(int i, int j, double v)
45 | {
46 | Trace.Assert(0 <= i && i < n);
47 | Trace.Assert(0 <= j && j < d);
48 | c[i * d + j] = v;
49 | }
50 |
51 | public override string ToString()
52 | {
53 | var sb = new StringBuilder('{');
54 | for (int i = 0; i < n; ++i)
55 | {
56 | sb.Append('[');
57 | for (int j = 0; j < d; ++j)
58 | {
59 | sb.Append(Coord(i, j));
60 | if (j < d - 1) sb.Append(",");
61 | }
62 | sb.Append(']');
63 | if (i < n - 1) sb.Append(", ");
64 | }
65 | sb.Append('}');
66 |
67 | return sb.ToString();
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/csharp/example/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using SEB;
3 |
4 | using static SEB.PointSetUtils;
5 |
6 | namespace example;
7 | class Program
8 | {
9 | static void Main(string[] args)
10 | {
11 | Console.WriteLine("====================================================");
12 | Console.WriteLine("Seb example");
13 |
14 | // Check for right number of arguments ...
15 | if (args.Length < 2)
16 | {
17 | Console.WriteLine($"Usage {AppDomain.CurrentDomain.FriendlyName} number-of-points dimension [boundary]");
18 | Console.WriteLine("If 'boundary' is given, all points will be on the boundary of a sphere.");
19 | Console.WriteLine("====================================================");
20 | Environment.Exit(1);
21 | }
22 | Console.WriteLine("====================================================");
23 |
24 | // ... and parse command line arguments
25 | var n = int.Parse(args[0]);
26 | var d = int.Parse(args[1]);
27 | var on_boundary = args.Length > 2 && args[2] == "boundary";
28 |
29 | // Construct n random points in dimension d
30 | var rnd = new Random();
31 | var S = RandomPointSet(d, n, rnd, on_boundary);
32 |
33 | var sw = new Stopwatch();
34 |
35 | Console.WriteLine("Starting computation...");
36 | Console.WriteLine("====================================================");
37 |
38 | sw.Start();
39 |
40 | var mb = new Miniball(S);
41 |
42 | var rad = mb.Radius;
43 | var rad_squared = mb.SquaredRadius;
44 | var center = mb.Center;
45 |
46 | sw.Stop();
47 |
48 | // Output
49 | Console.WriteLine($"Running time: {sw.Elapsed.TotalSeconds}s");
50 | Console.WriteLine($"Radius = {rad} (squared: {rad_squared})");
51 | Console.WriteLine("Center:");
52 | for (int j = 0; j < center.Length; ++j)
53 | Console.WriteLine($" {center[j]}");
54 |
55 | Console.WriteLine("====================================================");
56 | Console.Write(mb.Verify().ConsoleFmt());
57 | Console.WriteLine("====================================================");
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/java/src/test/java/com/dreizak/miniball/highdim/SubspanTest.java:
--------------------------------------------------------------------------------
1 | package com.dreizak.miniball.highdim;
2 |
3 | import static junit.framework.Assert.assertEquals;
4 | import static junit.framework.Assert.assertFalse;
5 | import static junit.framework.Assert.assertTrue;
6 |
7 | import org.junit.Test;
8 |
9 | import com.dreizak.miniball.model.ArrayPointSet;
10 |
11 | public class SubspanTest
12 | {
13 | final static double Tolerance = 1.0e-15; // TODO
14 |
15 | @Test
16 | public void subspan2x2WithLast()
17 | {
18 | // S = [ (1, 2), (5, 2)] in the plane
19 | ArrayPointSet S = new ArrayPointSet(2, 2);
20 | S.set(0, 0, 1);
21 | S.set(0, 1, 2);
22 | S.set(1, 0, 5);
23 | S.set(1, 1, 2);
24 |
25 | // Sub-span containing point 1 (i.e., the last one)
26 | Subspan span = new Subspan(2, S, 1);
27 | assertFalse(span.isMember(0));
28 | assertTrue(span.isMember(1));
29 | assertEquals(1, span.globalIndex(0));
30 | assertEquals(1, span.size());
31 | assertEquals(0.0, span.representationError());
32 |
33 | // Compute shortest vector to affine hull from a test point
34 | {
35 | double[] pt = {
36 | 0, 0
37 | }, expected = {
38 | 5, 2
39 | };
40 | shortestVectorToHull(span, pt, expected);
41 | }
42 |
43 | // Add point 0
44 | span.add(0);
45 | assertTrue(span.isMember(0));
46 | assertTrue(span.isMember(1));
47 | assertEquals(0, span.globalIndex(0));
48 | assertEquals(1, span.globalIndex(1));
49 | assertEquals(2, span.size());
50 | assertTrue(span.representationError() <= Tolerance);
51 |
52 | // Compute shortest vector to affine hull from a few test points
53 | {
54 | double[] pt = {
55 | 0, 0
56 | }, expected = {
57 | 0, 2
58 | };
59 | shortestVectorToHull(span, pt, expected);
60 | }
61 | {
62 | double[] pt = {
63 | 4, 1
64 | }, expected = {
65 | 0, 1
66 | };
67 | shortestVectorToHull(span, pt, expected);
68 | }
69 | {
70 | double[] pt = {
71 | 4, 2
72 | }, expected = {
73 | 0, 0
74 | };
75 | shortestVectorToHull(span, pt, expected);
76 | }
77 | }
78 |
79 | static void shortestVectorToHull(Subspan span, double[] pt, double[] expected)
80 | {
81 | double[] sv = new double[span.dimension()];
82 | span.shortestVectorToSpan(pt, sv);
83 | for (int i = 0; i < span.dimension(); ++i)
84 | assertTrue(Math.abs(expected[i] - sv[i]) <= Tolerance);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/csharp/test/SubspanTest.cs:
--------------------------------------------------------------------------------
1 | using SEB;
2 | using static System.Math;
3 |
4 | namespace test;
5 |
6 | public class SubspanTest
7 | {
8 | static double Tolerance = 1.0e-15; // TODO
9 |
10 | [Fact]
11 | public void subspan2x2WithLast()
12 | {
13 | // S = [ (1, 2), (5, 2)] in the plane
14 | var S = new ArrayPointSet(2, 2);
15 | S.Set(0, 0, 1);
16 | S.Set(0, 1, 2);
17 | S.Set(1, 0, 5);
18 | S.Set(1, 1, 2);
19 |
20 | // Sub-span containing point 1 (i.e., the last one)
21 | var span = new Subspan(2, S, 1);
22 | Assert.False(span.IsMember(0));
23 | Assert.True(span.IsMember(1));
24 | Assert.Equal(1, span.GlobalIndex(0));
25 | Assert.Equal(1, span.Size);
26 | Assert.Equal(0.0, span.RepresentationError());
27 |
28 | // Compute shortest vector to affine hull from a test point
29 | {
30 | double[] pt = {
31 | 0, 0
32 | }, expected = {
33 | 5, 2
34 | };
35 | ShortestVectorToHull(span, pt, expected);
36 | }
37 |
38 | // Add point 0
39 | span.Add(0);
40 | Assert.True(span.IsMember(0));
41 | Assert.True(span.IsMember(1));
42 | Assert.Equal(0, span.GlobalIndex(0));
43 | Assert.Equal(1, span.GlobalIndex(1));
44 | Assert.Equal(2, span.Size);
45 | Assert.True(span.RepresentationError() <= Tolerance);
46 |
47 | // Compute shortest vector to affine hull from a few test points
48 | {
49 | double[] pt = {
50 | 0, 0
51 | }, expected = {
52 | 0, 2
53 | };
54 | ShortestVectorToHull(span, pt, expected);
55 | }
56 | {
57 | double[] pt = {
58 | 4, 1
59 | }, expected = {
60 | 0, 1
61 | };
62 | ShortestVectorToHull(span, pt, expected);
63 | }
64 | {
65 | double[] pt = {
66 | 4, 2
67 | }, expected = {
68 | 0, 0
69 | };
70 | ShortestVectorToHull(span, pt, expected);
71 | }
72 | }
73 |
74 | static void ShortestVectorToHull(Subspan span, double[] pt, double[] expected)
75 | {
76 | var sv = new double[span.Dimension];
77 | span.ShortestVectorToSpan(pt, sv);
78 | for (int i = 0; i < span.Dimension; ++i)
79 | Assert.True(Abs(expected[i] - sv[i]) <= Tolerance);
80 | }
81 | }
--------------------------------------------------------------------------------
/python/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15...3.26)
2 |
3 | project(nanobind_example LANGUAGES CXX)
4 |
5 | if (NOT SKBUILD)
6 | message(WARNING "\
7 | This CMake file is meant to be executed using 'scikit-build'. Running
8 | it directly will almost certainly not produce the desired result. If
9 | you are a user trying to install this package, please use the command
10 | below, which will install all necessary build dependencies, compile
11 | the package in an isolated environment, and then install it.
12 | =====================================================================
13 | $ pip install .
14 | =====================================================================
15 | If you are a software developer, and this is your own package, then
16 | it is usually much more efficient to install the build dependencies
17 | in your environment once and use the following command that avoids
18 | a costly creation of a new virtual environment at every compilation:
19 | =====================================================================
20 | $ pip install nanobind scikit-build-core[pyproject]
21 | $ pip install --no-build-isolation -ve .
22 | =====================================================================
23 | You may optionally add -Ceditable.rebuild=true to auto-rebuild when
24 | the package is imported. Otherwise, you need to re-run the above
25 | after editing C++ files.")
26 | endif()
27 | # Enable diagnostic colors for ninja
28 | if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0)
29 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
30 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always")
31 | endif()
32 |
33 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
34 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
35 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcolor-diagnostics")
36 | endif()
37 |
38 | # Try to import all Python components potentially needed by nanobind
39 | find_package(Python 3.8
40 | REQUIRED COMPONENTS Interpreter Development.Module
41 | OPTIONAL_COMPONENTS Development.SABIModule)
42 |
43 | # Import nanobind through CMake's find_package mechanism
44 | find_package(nanobind CONFIG REQUIRED)
45 |
46 | # We are now ready to compile the actual extension module
47 | nanobind_add_module(
48 | # Name of the extension. We wrap the code, so this does not matter
49 | _miniball
50 |
51 | # Target the stable ABI for Python 3.12+
52 | STABLE_ABI
53 |
54 | # Build libnanobind statically and merge it into the
55 | # extension (which itself remains a shared library)
56 | NB_STATIC
57 |
58 | # Source code goes here
59 | miniball_python.cpp
60 | )
61 |
62 | # Install directive for scikit-build-core
63 | install(TARGETS _miniball LIBRARY DESTINATION miniball)
64 |
--------------------------------------------------------------------------------
/material/old/run_cplex.C:
--------------------------------------------------------------------------------
1 | // Synopsis: Runs the CPLEX 'baropt' solver on a given QP problem
2 | // instance which is given as a MPS file.
3 | //
4 | // Usage: run_cplex mps-file
5 | //
6 | // Authors: Martin Kutz ,
7 | // Kaspar Fischer
8 | //
9 | // Revision: $Revision: 1094 $ ($Date: 2004-09-02 12:42:47 +0200 (Thu, 02 Sep 2004) $)
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | // We include Seb.h only because we use the timer in there:
17 | #include
18 |
19 | int main(int argn,char **argv) {
20 | using std::cout;
21 | using std::endl;
22 | using std::string;
23 |
24 | int status; // CPLEX status
25 | CPXENVptr env = NULL;
26 | CPXLPptr instance = NULL;
27 |
28 | try {
29 | // check paramaterss:
30 | if (argn < 2)
31 | throw string("no MPS file name specified as argument to program");
32 |
33 | // initialize CPLEX environment:
34 | if ((env = CPXopenCPLEXdevelop(&status)) == NULL)
35 | throw string("couldn't open CPLEX environment");
36 |
37 | // create problem instance:
38 | if ((instance = CPXcreateprob(env,&status,"Miniball instance")) == NULL)
39 | throw string("couldn't create CPLEX problem instance");
40 |
41 | // read MPS file:
42 | if ((status = CPXreadcopyprob(env,instance,argv[1],NULL)) != 0)
43 | throw string("coudn't read problem from MPS file");
44 |
45 | // start timer:
46 | Seb::Timer::instance().start("cplex");
47 |
48 | // solve using Barrier solver:
49 | if ((status = CPXbaropt(env,instance)) != 0)
50 | throw string("coudn't solve problem instance");
51 |
52 | // get objective value (i.e., the squared radius):
53 | double radius_square;
54 | if ((status = CPXgetobjval(env,instance,&radius_square)) != 0)
55 | throw string("couldn't get objective value");
56 |
57 | // output:
58 | cout << "====================================================" << endl
59 | << "Input file: " << argv[1] << endl
60 | << "====================================================" << endl
61 | << "Running time: " << Seb::Timer::instance().lapse("cplex")
62 | << "s" << endl
63 | << "Squared radius: " << std::setprecision(17)
64 | << std::setiosflags(std::ios::scientific)
65 | << radius_square << endl
66 | << "====================================================" << endl;
67 | }
68 |
69 | // error handling:
70 | catch (std::string msg) {
71 | cout << "Error: " << msg << "." << endl;
72 |
73 | // fetch CPLEX error string from status:
74 | if (env != NULL) {
75 | char errormsg[1024];
76 | CPXgeterrorstring(env,status,errormsg);
77 | cout << "CPLEX message: " << errormsg << endl;
78 | }
79 | }
80 |
81 | // deallocate resources:
82 | if (instance != NULL)
83 | CPXfreeprob(env,&instance);
84 | if (env != NULL)
85 | CPXcloseCPLEX(&env);
86 | }
87 |
--------------------------------------------------------------------------------
/cpp/test/example.C:
--------------------------------------------------------------------------------
1 | // Synopsis: Example program illustrating how to use the Seb library
2 | //
3 | // Authors: Martin Kutz ,
4 | // Kaspar Fischer
5 |
6 | #include
7 | #include
8 |
9 | #include "Seb.h"
10 | #include "Seb_debug.h"
11 | #include "Seb_debug.C" // ... only needed because we use Seb::Timer below
12 |
13 | int main(int argn,char **argv) {
14 | typedef double FT;
15 | typedef Seb::Point Point;
16 | typedef std::vector PointVector;
17 | typedef Seb::Smallest_enclosing_ball Miniball;
18 |
19 | using std::cout;
20 | using std::endl;
21 | using std::vector;
22 |
23 | cout << "====================================================" << endl
24 | << "Seb example" << endl;
25 |
26 | // Check for right number of arguments ...
27 | if (argn < 3) {
28 | cout << "Usage: " << argv[0] << " number-of-points dimension [boundary]" << endl
29 | << "If 'boundary' is given, all points will be on the boundary of a sphere." << endl
30 | << "====================================================" << endl;
31 | return 1;
32 | }
33 | cout << "====================================================" << endl;
34 | // ... and parse command line arguments
35 | const int n = std::atoi(argv[1]), d = std::atoi(argv[2]);
36 | const bool on_boundary = argn > 3 && std::string(argv[3]) == "boundary";
37 |
38 | // Construct n random points in dimension d
39 | PointVector S;
40 | vector coords(d);
41 | srand(clock());
42 | for (int i=0; i(2.0*rand()/RAND_MAX - 1.0);
48 | len += coords[j]*coords[j];
49 | }
50 |
51 | // Normalize length to "almost" 1 (makes it harder for the algorithm)
52 | if (on_boundary) {
53 | const double Wiggle = 1e-2;
54 | len = 1/(std::sqrt(len)+Wiggle*rand()/RAND_MAX);
55 | for (int j=0; j
47 | * The stream is assumed to be encoded in UTF-8 and should contain integers and double values, all
48 | * separated by space or return. The first two numbers must be integers, specifying the number of
49 | * points in the point set and the dimension. The following numbers are all doubles and specify
50 | * the points by their Euclidean coordinates.
51 | *
52 | * For example, the three two-dimensional points {@code (0,0)}, {@code (2,3)}, {@code (4,5)} could
53 | * be stored as follows:
54 | *
55 | *