summaryrefslogtreecommitdiff
path: root/wasserstein
diff options
context:
space:
mode:
Diffstat (limited to 'wasserstein')
-rw-r--r--wasserstein/CMakeLists.txt62
-rw-r--r--wasserstein/README100
-rw-r--r--wasserstein/example/wasserstein_dist.cpp156
-rw-r--r--wasserstein/example/wasserstein_dist_dipha.cpp133
-rw-r--r--wasserstein/example/wasserstein_dist_point_cloud.cpp175
-rw-r--r--wasserstein/include/auction_oracle.h40
-rw-r--r--wasserstein/include/auction_oracle_base.h85
-rw-r--r--wasserstein/include/auction_oracle_base.hpp97
-rw-r--r--wasserstein/include/auction_oracle_kdtree_pure_geom.h94
-rw-r--r--wasserstein/include/auction_oracle_kdtree_pure_geom.hpp225
-rw-r--r--wasserstein/include/auction_oracle_kdtree_restricted.h119
-rw-r--r--wasserstein/include/auction_oracle_kdtree_restricted.hpp538
-rw-r--r--wasserstein/include/auction_oracle_kdtree_single_diag.h219
-rw-r--r--wasserstein/include/auction_oracle_kdtree_single_diag.hpp717
-rw-r--r--wasserstein/include/auction_oracle_lazy_heap.h191
-rw-r--r--wasserstein/include/auction_oracle_lazy_heap.hpp465
-rw-r--r--wasserstein/include/auction_oracle_stupid_sparse_restricted.h112
-rw-r--r--wasserstein/include/auction_oracle_stupid_sparse_restricted.hpp521
-rw-r--r--wasserstein/include/auction_runner_fr.h272
-rw-r--r--wasserstein/include/auction_runner_fr.hpp1208
-rw-r--r--wasserstein/include/auction_runner_gs.h122
-rw-r--r--wasserstein/include/auction_runner_gs.hpp494
-rw-r--r--wasserstein/include/auction_runner_gs_single_diag.h149
-rw-r--r--wasserstein/include/auction_runner_gs_single_diag.hpp738
-rw-r--r--wasserstein/include/auction_runner_jac.h230
-rw-r--r--wasserstein/include/auction_runner_jac.hpp879
-rw-r--r--wasserstein/include/basic_defs_ws.h321
-rw-r--r--wasserstein/include/basic_defs_ws.hpp220
-rw-r--r--wasserstein/include/def_debug_ws.h44
-rw-r--r--wasserstein/include/diagonal_heap.h149
-rw-r--r--wasserstein/include/diagram_reader.h447
-rw-r--r--wasserstein/include/dnn/geometry/euclidean-dynamic.h270
-rw-r--r--wasserstein/include/dnn/geometry/euclidean-fixed.h196
-rw-r--r--wasserstein/include/dnn/local/kd-tree.h97
-rw-r--r--wasserstein/include/dnn/local/kd-tree.hpp330
-rw-r--r--wasserstein/include/dnn/local/search-functors.h95
-rw-r--r--wasserstein/include/dnn/parallel/tbb.h235
-rw-r--r--wasserstein/include/dnn/parallel/utils.h100
-rw-r--r--wasserstein/include/dnn/utils.h47
-rw-r--r--wasserstein/include/hera_infinity.h22
-rwxr-xr-xwasserstein/include/opts/opts.h353
-rw-r--r--wasserstein/include/wasserstein.h346
-rw-r--r--wasserstein/include/wasserstein_pure_geom.hpp86
-rw-r--r--wasserstein/tests/data/test_100_A100
-rw-r--r--wasserstein/tests/data/test_100_A.pd.diphabin0 -> 2424 bytes
-rw-r--r--wasserstein/tests/data/test_100_B100
-rw-r--r--wasserstein/tests/data/test_100_B.pd.diphabin0 -> 2424 bytes
-rw-r--r--wasserstein/tests/data/test_200_A200
-rw-r--r--wasserstein/tests/data/test_200_B200
-rw-r--r--wasserstein/tests/data/test_5000_A5000
-rw-r--r--wasserstein/tests/data/test_5000_B5000
-rw-r--r--wasserstein/tests/data/test_5_A5
-rw-r--r--wasserstein/tests/data/test_5_A.pd.diphabin0 -> 144 bytes
-rw-r--r--wasserstein/tests/data/test_5_B5
-rw-r--r--wasserstein/tests/data/test_5_B.pd.diphabin0 -> 144 bytes
-rw-r--r--wasserstein/tests/data/test_diag1_A1
-rw-r--r--wasserstein/tests/data/test_diag1_A.pd.diphabin0 -> 48 bytes
-rw-r--r--wasserstein/tests/data/test_diag1_B1
-rw-r--r--wasserstein/tests/data/test_diag1_B.pd.diphabin0 -> 48 bytes
-rw-r--r--wasserstein/tests/data/test_diag2_A1
-rw-r--r--wasserstein/tests/data/test_diag2_A.pd.diphabin0 -> 48 bytes
-rw-r--r--wasserstein/tests/data/test_diag2_B1
-rw-r--r--wasserstein/tests/data/test_diag2_B.pd.diphabin0 -> 48 bytes
-rw-r--r--wasserstein/tests/data/test_diag3_A220
-rw-r--r--wasserstein/tests/data/test_diag3_A.pd.diphabin0 -> 5304 bytes
-rw-r--r--wasserstein/tests/data/test_diag3_B193
-rw-r--r--wasserstein/tests/data/test_diag3_B.pd.diphabin0 -> 4656 bytes
-rw-r--r--wasserstein/tests/data/test_list.txt21
-rw-r--r--wasserstein/tests/test_hera_wasserstein.cpp532
-rw-r--r--wasserstein/tests/test_hera_wasserstein_pure_geom.cpp111
-rw-r--r--wasserstein/tests/tests_main.cpp3
-rw-r--r--wasserstein/tests/tests_reader.h67
72 files changed, 23260 insertions, 0 deletions
diff --git a/wasserstein/CMakeLists.txt b/wasserstein/CMakeLists.txt
new file mode 100644
index 0000000..dea4550
--- /dev/null
+++ b/wasserstein/CMakeLists.txt
@@ -0,0 +1,62 @@
+project (wasserstein)
+cmake_minimum_required (VERSION 3.5.1)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+include (GenerateExportHeader)
+
+include(TestBigEndian)
+test_big_endian(BIG_ENDIAN)
+if(BIG_ENDIAN)
+ add_definitions(-DBIGENDIAN)
+endif()
+
+# Default to Release
+
+if (NOT CMAKE_BUILD_TYPE)
+ set (CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
+endif (NOT CMAKE_BUILD_TYPE)
+
+# Boost
+find_package (Boost)
+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include
+ SYSTEM ${Boost_INCLUDE_DIR})
+
+if(NOT WIN32)
+ add_definitions(-std=c++14)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -ggdb -D_GLIBCXX_DEBUG")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 ")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O2 -g -ggdb")
+endif(NOT WIN32)
+
+file(GLOB WS_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp)
+
+#add_library(wasserstein ${WS_SOURCES})
+
+#if (WIN32)
+ #GENERATE_EXPORT_HEADER(wasserstein
+ #BASE_NAME wasserstein
+ #EXPORT_MACRO_NAME wasserstein_EXPORT
+ #EXPORT_FILE_NAME wasserstein_export.h
+ #STATIC_DEFINE wasserstein_BUILT_AS_STATIC)
+#endif(WIN32)
+
+find_package (Threads)
+set (libraries ${libraries} ${CMAKE_THREAD_LIBS_INIT})
+
+add_executable(wasserstein_dist ${CMAKE_CURRENT_SOURCE_DIR}/example/wasserstein_dist.cpp ${WS_HEADERS} include/hera_infinity.h)
+target_link_libraries(wasserstein_dist PUBLIC ${libraries})
+
+add_executable(wasserstein_dist_dipha ${CMAKE_CURRENT_SOURCE_DIR}/example/wasserstein_dist_dipha.cpp ${WS_HEADERS} include/hera_infinity.h)
+target_link_libraries(wasserstein_dist_dipha PUBLIC ${libraries})
+
+# pure geometric version, arbitrary dimension
+add_executable(wasserstein_dist_point_cloud ${CMAKE_CURRENT_SOURCE_DIR}/example/wasserstein_dist_point_cloud.cpp ${WS_HEADERS} include/hera_infinity.h)
+target_link_libraries(wasserstein_dist_point_cloud PUBLIC ${libraries})
+
+# Tests
+add_executable(wasserstein_test ${CMAKE_CURRENT_SOURCE_DIR}/tests/tests_main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_hera_wasserstein.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_hera_wasserstein_pure_geom.cpp include/hera_infinity.h tests/tests_reader.h)
+#add_executable(wasserstein_test EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_hera_wasserstein.cpp)
+target_link_libraries(wasserstein_test PUBLIC ${libraries})
diff --git a/wasserstein/README b/wasserstein/README
new file mode 100644
index 0000000..5228d63
--- /dev/null
+++ b/wasserstein/README
@@ -0,0 +1,100 @@
+This is a program for computing Wasserstein distances between persistence
+diagrams using the geometric version of auction algorithm.
+
+Accompanying paper: M. Kerber, D. Morozov, A. Nigmetov. Geometry Helps To Compare
+Persistence Diagrams (ALENEX 2016, http://www.geometrie.tugraz.at/nigmetov/geom_dist.pdf)
+Bug reports can be sent to "nigmetov EMAIL SIGN tugraz DOT at".
+
+Wasserstein distance $W_{q, p}(X, Y)$ between two persistent diagrams is
+the minimum over all perfect matchings between $X$ and $Y$ ( $y(x)$ is the point of $Y$
+matched to $x \in X$ ) of the following expression:
+$ ( \sum \| x - y(x) \|_p ^ { q } ) ^ { 1 / q} $
+
+# Dependencies
+
+Requires boost 1.58 or higher.
+Your compiler must support C++11.
+
+# Usage:
+
+To use a standalone command-line utility wasserstein_dist:
+
+wasserstein_dist file1 file2 [wasserstein degree] [relative error] [internal norm].
+
+Parameter wasserstein degree corresponds to $q$, when it tends to infinity,
+Wasserstein distance tends to the bottleneck distance.
+
+If two diagrams are equal, then the exact distance 0.0 is printed (the order
+of points in file1 and file2 need not be the same).
+Otherwise the output is an approximation of the exact distance. Precisely:
+if d_exact is the true distance and d_approx is the output, then
+
+ | d_exact - d_approx | / d_exact < relative_error.
+
+Parameter internal_p corresponds to p.
+
+Default values:
+wasserstein_degree = 1.0,
+relative_error = 0.01,
+internal_p = infinity.
+
+Valid values:
+wasserstein_degree must be in $[1.0, \infinity)$,
+relative_error must be positive,
+internal_p must be in $[1.0, \infinity]$ (to explicitly set internal_p to $\infinity$, supply inf).By default wasserstein degree is 1.0, relative error is 0.01, internal norm is l_infinity.
+
+file1 and file2 must contain persistence diagrams in plain text format
+(one point per line, empty lines are ignored, comments can be made with #):
+
+# this is how your input can look like
+x_1 y_1 # two real numbers per line
+...
+# empty lines or comments are ignored
+x_n y_n
+
+To use from your code:
+
+#include "wasserstein.h"
+
+// All classes and functions are in geom_ws namespace
+
+std::vector<std::pair<double, double>> diagram1, diagram2;
+// any container class that supports range-for loops will do.
+// A pair represents a single point,
+// first component = x-coordinate,
+// second component = y-coordinate.
+// ...
+// load your diagrams into diagram1, diagram2 (off-diagonal points).
+// You can use function readDiagramPointSet:
+geom_ws::readDiagramPointSet("diagram1.txt", diagram1);
+geom_ws::readDiagramPointSet("diagram2.txt", diagram1);
+// ...
+// to get the distance:
+double wsDist = geom_ws::wassersteinDist(diagram1, diagram2, q, delta, p);
+// q is wasserstein degree, delta is relative error,
+// p is the internal norm in Wasserstein distance, defaults to infinity
+
+Necessary projections (diagonal points) will be added in the wassersteinDist
+function.
+
+See also code in wasserstein/example/wasserstein_dist.cpp.
+
+# License
+
+See ../license.txt
+
+# Building
+
+CMakeLists.txt in the root directory can be used to make the library (contained
+in wasserstein/src/ directory) and the command-line utility (in wasserstein/example/ directory)
+to compute the distance between two diagrams in txt files.
+
+On Linux/Mac:
+
+mkdir build
+cd build
+cmake ..
+make
+
+On Windows (checked with Visual Studio 2015, Community version)
+use cmake-gui to create the solution in build directory and build it with VS.
diff --git a/wasserstein/example/wasserstein_dist.cpp b/wasserstein/example/wasserstein_dist.cpp
new file mode 100644
index 0000000..cbe83e2
--- /dev/null
+++ b/wasserstein/example/wasserstein_dist.cpp
@@ -0,0 +1,156 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#include <iostream>
+#include <locale>
+#include <iomanip>
+#include <vector>
+
+#include "opts/opts.h"
+
+//#define LOG_AUCTION
+
+//#include "auction_runner_fr.h"
+//#include "auction_runner_fr.hpp"
+
+#include "wasserstein.h"
+
+// any container of pairs of Reals can be used,
+// we use vector in this example.
+
+int main(int argc, char* argv[])
+{
+ using Real = double;
+ using PairVector = std::vector<std::pair<Real, Real>>;
+ PairVector diagramA, diagramB;
+
+ hera::AuctionParams<Real> params;
+ params.max_num_phases = 800;
+
+ opts::Options ops(argc, argv);
+ ops >> opts::Option('q', "degree", params.wasserstein_power, "Wasserstein degree")
+ >> opts::Option('d', "error", params.delta, "Relative error")
+ >> opts::Option('p', "internal-p", params.internal_p, "Internal norm")
+ >> opts::Option("initial-epsilon", params.initial_epsilon, "Initial epsilon")
+ >> opts::Option("epsilon-factor", params.epsilon_common_ratio, "Epsilon factor")
+ >> opts::Option("max-bids-per-round", params.max_bids_per_round, "Maximal number of bids per round")
+ >> opts::Option('m', "max-rounds", params.max_num_phases, "Maximal number of iterations");
+
+
+ bool print_relative_error = ops >> opts::Present('e', "--print-error", "Print real relative error");
+
+ params.tolerate_max_iter_exceeded = ops >> opts::Present('t', "tolerate", "Suppress max-iterations-exceeded error and print the best result.");
+
+ std::string dgm_fname_1, dgm_fname_2;
+ bool dgm_1_given = (ops >> opts::PosOption(dgm_fname_1));
+ bool dgm_2_given = (ops >> opts::PosOption(dgm_fname_2));
+
+ //std::cout << "q = " << params.wasserstein_power << ", delta = " << params.delta << ", p = " << params.internal_p << ", max_round = " << params.max_num_phases << std::endl;
+ //std::cout << "print relative error: " << print_relative_error << std::endl;
+ //std::cout << "dgm1: " << dgm_fname_1 << std::endl;
+ //std::cout << "dgm2: " << dgm_fname_2 << std::endl;
+
+ if (not dgm_1_given or not dgm_2_given) {
+ std::cerr << "Usage: " << argv[0] << " file1 file2 " << std::endl;
+ std::cerr << "compute Wasserstein distance between persistence diagrams in file1 and file2.\n";
+ std::cerr << ops << std::endl;
+ return 1;
+ }
+
+ if (ops >> opts::Present('h', "help", "show help message")) {
+ std::cout << "Usage: " << argv[0] << " file1 file2 " << std::endl;
+ std::cout << "compute Wasserstein distance between persistence diagrams in file1 and file2.\n";
+ std::cout << ops << std::endl;
+ }
+
+ if (!hera::read_diagram_point_set<Real, PairVector>(dgm_fname_1, diagramA)) {
+ std::exit(1);
+ }
+
+ if (!hera::read_diagram_point_set(dgm_fname_2, diagramB)) {
+ std::exit(1);
+ }
+
+ if (params.wasserstein_power < 1.0) {
+ std::cerr << "Wasserstein_degree was \"" << params.wasserstein_power << "\", must be a number >= 1.0. Cannot proceed. " << std::endl;
+ std::exit(1);
+ }
+
+ if (params.wasserstein_power == 1.0) {
+ hera::remove_duplicates<Real>(diagramA, diagramB);
+ }
+
+ //default relative error: 1%
+ if ( params.delta <= 0.0) {
+ std::cerr << "relative error was \"" << params.delta << "\", must be a number > 0.0. Cannot proceed. " << std::endl;
+ std::exit(1);
+ }
+
+ // default for internal metric is l_infinity
+ if (std::isinf(params.internal_p)) {
+ params.internal_p = hera::get_infinity<Real>();
+ }
+
+
+ if (not hera::is_p_valid_norm<Real>(params.internal_p)) {
+ std::cerr << "internal-p was \"" << params.internal_p << "\", must be a number >= 1.0 or inf. Cannot proceed. " << std::endl;
+ std::exit(1);
+ }
+
+ // if you want to specify initial value for epsilon and the factor
+ // for epsilon-scaling
+ if (params.initial_epsilon < 0.0) {
+ std::cerr << "initial-epsilon was \"" << params.initial_epsilon << "\", must be a non-negative number. Cannot proceed." << std::endl;
+ std::exit(1);
+ }
+
+ if (params.epsilon_common_ratio <= 1.0 and params.epsilon_common_ratio != 0.0) {
+ std::cerr << "The 7th argument (epsilon factor) was \"" << params.epsilon_common_ratio << "\", must be a number greater than 1. Cannot proceed." << std::endl;
+ std::exit(1);
+ }
+
+ if (params.max_bids_per_round == 0)
+ params.max_bids_per_round = std::numeric_limits<decltype(params.max_bids_per_round)>::max();
+
+
+ std::string log_filename_prefix = ( 11 <= argc ) ? argv[10] : "";
+
+
+#ifdef LOG_AUCTION
+ spdlog::set_level(spdlog::level::info);
+#endif
+
+ Real res = hera::wasserstein_dist(diagramA, diagramB, params, log_filename_prefix);
+
+ std::cout << std::setprecision(15) << res << std::endl;
+ if (print_relative_error)
+ std::cout << "Relative error: " << params.final_relative_error << std::endl;
+
+ return 0;
+
+}
diff --git a/wasserstein/example/wasserstein_dist_dipha.cpp b/wasserstein/example/wasserstein_dist_dipha.cpp
new file mode 100644
index 0000000..2ed9c2c
--- /dev/null
+++ b/wasserstein/example/wasserstein_dist_dipha.cpp
@@ -0,0 +1,133 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+Copyright (c) 2018, G. Spreemann
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#include <iostream>
+#include <locale>
+#include <iomanip>
+#include <vector>
+
+//#define LOG_AUCTION
+
+//#include "auction_runner_fr.h"
+//#include "auction_runner_fr.hpp"
+
+#include "wasserstein.h"
+
+// any container of pairs of doubles can be used,
+// we use vector in this example.
+
+int main(int argc, char* argv[])
+{
+ using PairVector = std::vector<std::pair<double, double>>;
+ PairVector diagramA, diagramB;
+
+ hera::AuctionParams<double> params;
+
+ if (argc < 4 ) {
+ std::cerr << "Usage: " << argv[0] << " file1 file2 ph_dim [wasserstein_degree] [relative_error] [internal norm] [initial epsilon] [epsilon_factor] [max_bids_per_round] [gamma_threshold][log_filename_prefix]. By default power is 1.0, relative error is 0.01, internal norm is l_infinity, initall epsilon is chosen automatically, epsilon factor is 5.0, Jacobi variant is used (max bids per round is maximal), gamma_threshold = 0.0." << std::endl;
+ return 1;
+ }
+
+ unsigned int dim = std::stoul(argv[3]);
+
+ if (!hera::read_diagram_dipha<double, PairVector>(argv[1], dim, diagramA)) {
+ std::exit(1);
+ }
+
+ if (!hera::read_diagram_dipha<double, PairVector>(argv[2], dim, diagramB)) {
+ std::exit(1);
+ }
+
+ params.wasserstein_power = (5 <= argc) ? atof(argv[4]) : 1.0;
+ if (params.wasserstein_power < 1.0) {
+ std::cerr << "The third argument (wasserstein_degree) was \"" << argv[4] << "\", must be a number >= 1.0. Cannot proceed. " << std::endl;
+ std::exit(1);
+ }
+
+ if (params.wasserstein_power == 1.0) {
+ hera::remove_duplicates<double>(diagramA, diagramB);
+ }
+
+ //default relative error: 1%
+ params.delta = (6 <= argc) ? atof(argv[5]) : 0.01;
+ if ( params.delta <= 0.0) {
+ std::cerr << "The 4th argument (relative error) was \"" << argv[5] << "\", must be a number > 0.0. Cannot proceed. " << std::endl;
+ std::exit(1);
+ }
+
+ // default for internal metric is l_infinity
+ params.internal_p = ( 7 <= argc ) ? atof(argv[6]) : hera::get_infinity<double>();
+ if (std::isinf(params.internal_p)) {
+ params.internal_p = hera::get_infinity<double>();
+ }
+
+
+ if (not hera::is_p_valid_norm<double>(params.internal_p)) {
+ std::cerr << "The 6th argument (internal norm) was \"" << argv[6] << "\", must be a number >= 1.0 or inf. Cannot proceed. " << std::endl;
+ std::exit(1);
+ }
+
+ // if you want to specify initial value for epsilon and the factor
+ // for epsilon-scaling
+ params.initial_epsilon= ( 8 <= argc ) ? atof(argv[7]) : 0.0 ;
+
+ if (params.initial_epsilon < 0.0) {
+ std::cerr << "The 7th argument (initial epsilon) was \"" << argv[7] << "\", must be a non-negative number. Cannot proceed." << std::endl;
+ std::exit(1);
+ }
+
+ params.epsilon_common_ratio = ( 9 <= argc ) ? atof(argv[8]) : 0.0 ;
+ if (params.epsilon_common_ratio <= 1.0 and params.epsilon_common_ratio != 0.0) {
+ std::cerr << "The 8th argument (epsilon factor) was \"" << argv[8] << "\", must be a number greater than 1. Cannot proceed." << std::endl;
+ std::exit(1);
+ }
+
+
+ params.max_bids_per_round = ( 10 <= argc ) ? atoi(argv[9]) : 0;
+ if (params.max_bids_per_round == 0)
+ params.max_bids_per_round = std::numeric_limits<decltype(params.max_bids_per_round)>::max();
+
+
+ params.gamma_threshold = (11 <= argc) ? atof(argv[10]) : 0.0;
+
+ std::string log_filename_prefix = ( 12 <= argc ) ? argv[11] : "";
+
+ params.max_num_phases = 800;
+
+#ifdef LOG_AUCTION
+ spdlog::set_level(spdlog::level::info);
+#endif
+
+ double res = hera::wasserstein_dist(diagramA, diagramB, params, log_filename_prefix);
+
+ std::cout << std::setprecision(15) << res << std::endl;
+
+ return 0;
+
+}
diff --git a/wasserstein/example/wasserstein_dist_point_cloud.cpp b/wasserstein/example/wasserstein_dist_point_cloud.cpp
new file mode 100644
index 0000000..ab7ff4f
--- /dev/null
+++ b/wasserstein/example/wasserstein_dist_point_cloud.cpp
@@ -0,0 +1,175 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#include <iostream>
+#include <locale>
+#include <iomanip>
+#include <vector>
+
+#include "wasserstein_pure_geom.hpp"
+
+int main(int argc, char* argv[])
+{
+
+ //{
+ //int n_points = 3;
+ //int dim = 3;
+ //using Traits = hera::ws::dnn::DynamicPointTraits<double>;
+ //hera::ws::dnn::DynamicPointTraits<double> traits(dim);
+ //hera::ws::dnn::DynamicPointVector<double> dgm_a = traits.container(n_points);
+ //hera::ws::dnn::DynamicPointVector<double> dgm_b = traits.container(n_points);
+
+ //dgm_a[0][0] = 0.0;
+ //dgm_a[0][1] = 0.0;
+ //dgm_a[0][2] = 0.0;
+
+ //dgm_a[1][0] = 1.0;
+ //dgm_a[1][1] = 0.0;
+ //dgm_a[1][2] = 0.0;
+
+ //dgm_a[2][0] = 0.0;
+ //dgm_a[2][1] = 1.0;
+ //dgm_a[2][2] = 1.0;
+
+ //dgm_b[0][0] = 0.0;
+ //dgm_b[0][1] = 0.1;
+ //dgm_b[0][2] = 0.1;
+
+ //dgm_b[1][0] = 1.1;
+ //dgm_b[1][1] = 0.0;
+ //dgm_b[1][2] = 0.0;
+
+ //dgm_b[2][0] = 0.0;
+ //dgm_b[2][1] = 1.1;
+ //dgm_b[2][2] = 0.9;
+
+
+ //hera::AuctionParams<double> params;
+ //params.dim = dim;
+
+
+ //std::cout << hera::ws::wasserstein_cost(dgm_a, dgm_b, params) << std::endl;
+
+ //return 0;
+ //}
+
+
+ using Real = double;
+ using PointVector = hera::ws::dnn::DynamicPointVector<Real>;
+ PointVector set_A, set_B;
+
+ hera::AuctionParams<Real> params;
+
+ if (argc < 3 ) {
+ std::cerr << "Usage: " << argv[0] << " file1 file2 [wasserstein_degree] [relative_error] [internal norm] [initial epsilon] [epsilon_factor] [max_bids_per_round] [gamma_threshold][log_filename_prefix]. By default power is 1.0, relative error is 0.01, internal norm is l_infinity, initall epsilon is chosen automatically, epsilon factor is 5.0, Jacobi variant is used (max bids per round is maximal), gamma_threshold = 0.0." << std::endl;
+ return 1;
+ }
+
+ int dimension_A, dimension_B;
+
+ if (!hera::read_point_cloud<Real>(argv[1], set_A, dimension_A)) {
+ std::exit(1);
+ }
+
+ if (!hera::read_point_cloud(argv[2], set_B, dimension_B)) {
+ std::exit(1);
+ }
+
+ if (dimension_A != dimension_B) {
+ std::cerr << "Dimension mismatch: " << dimension_A << " != " << dimension_B << std::endl;
+ std::exit(1);
+ }
+
+ params.dim = dimension_A;
+
+ params.wasserstein_power = (4 <= argc) ? atof(argv[3]) : 1.0;
+ if (params.wasserstein_power < 1.0) {
+ std::cerr << "The third argument (wasserstein_degree) was \"" << argv[3] << "\", must be a number >= 1.0. Cannot proceed. " << std::endl;
+ std::exit(1);
+ }
+
+ //if (params.wasserstein_power == 1.0) {
+ // hera::remove_duplicates<double?(set_A, set_B);
+ //}
+
+ //default relative error: 1%
+ params.delta = (5 <= argc) ? atof(argv[4]) : 0.01;
+ if ( params.delta <= 0.0) {
+ std::cerr << "The 4th argument (relative error) was \"" << argv[4] << "\", must be a number > 0.0. Cannot proceed. " << std::endl;
+ std::exit(1);
+ }
+
+ // default for internal metric is l_infinity
+ params.internal_p = ( 6 <= argc ) ? atof(argv[5]) : hera::get_infinity<Real>();
+ if (std::isinf(params.internal_p)) {
+ params.internal_p = hera::get_infinity<Real>();
+ }
+
+
+ if (not hera::is_p_valid_norm<Real>(params.internal_p)) {
+ std::cerr << "The 5th argument (internal norm) was \"" << argv[5] << "\", must be a number >= 1.0 or inf. Cannot proceed. " << std::endl;
+ std::exit(1);
+ }
+
+ // if you want to specify initial value for epsilon and the factor
+ // for epsilon-scaling
+ params.initial_epsilon= ( 7 <= argc ) ? atof(argv[6]) : 0.0 ;
+
+ if (params.initial_epsilon < 0.0) {
+ std::cerr << "The 6th argument (initial epsilon) was \"" << argv[6] << "\", must be a non-negative number. Cannot proceed." << std::endl;
+ std::exit(1);
+ }
+
+ params.epsilon_common_ratio = ( 8 <= argc ) ? atof(argv[7]) : 0.0 ;
+ if (params.epsilon_common_ratio <= 1.0 and params.epsilon_common_ratio != 0.0) {
+ std::cerr << "The 7th argument (epsilon factor) was \"" << argv[7] << "\", must be a number greater than 1. Cannot proceed." << std::endl;
+ std::exit(1);
+ }
+
+
+ params.max_bids_per_round = ( 9 <= argc ) ? atoi(argv[8]) : 0;
+ if (params.max_bids_per_round == 0)
+ params.max_bids_per_round = std::numeric_limits<decltype(params.max_bids_per_round)>::max();
+
+
+ params.gamma_threshold = (10 <= argc) ? atof(argv[9]) : 0.0;
+
+ std::string log_filename_prefix = ( 11 <= argc ) ? argv[10] : "";
+
+ params.max_num_phases = 800;
+
+#ifdef LOG_AUCTION
+ spdlog::set_level(spdlog::level::critical);
+#endif
+
+ Real res = hera::ws::wasserstein_dist(set_A, set_B, params);
+
+ std::cout << std::setprecision(15) << res << std::endl;
+
+ return 0;
+}
diff --git a/wasserstein/include/auction_oracle.h b/wasserstein/include/auction_oracle.h
new file mode 100644
index 0000000..d285a1f
--- /dev/null
+++ b/wasserstein/include/auction_oracle.h
@@ -0,0 +1,40 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef HERA_AUCTION_ORACLE_H
+#define HERA_AUCTION_ORACLE_H
+
+// all oracle classes are in separate h-hpp files
+// this file comprises all of them
+
+#include "auction_oracle_base.h"
+#include "auction_oracle_kdtree_restricted.h"
+#include "auction_oracle_kdtree_single_diag.h"
+#include "auction_oracle_stupid_sparse_restricted.h"
+
+#endif // HERA_AUCTION_ORACLE_H
diff --git a/wasserstein/include/auction_oracle_base.h b/wasserstein/include/auction_oracle_base.h
new file mode 100644
index 0000000..08eaf00
--- /dev/null
+++ b/wasserstein/include/auction_oracle_base.h
@@ -0,0 +1,85 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_ORACLE_BASE_H
+#define AUCTION_ORACLE_BASE_H
+
+#include <map>
+#include <memory>
+#include <set>
+#include <list>
+
+#include "basic_defs_ws.h"
+
+namespace hera {
+namespace ws {
+
+
+template <class Real>
+struct DebugOptimalBid {
+ DebugOptimalBid() : best_item_idx(k_invalid_index), best_item_value(-666.666), second_best_item_idx(k_invalid_index), second_best_item_value(-666.666) {};
+ IdxType best_item_idx;
+ Real best_item_value;
+ IdxType second_best_item_idx;
+ Real second_best_item_value;
+};
+
+template <class Real = double, class PointContainer_ = std::vector<DiagramPoint<Real>>>
+struct AuctionOracleBase {
+ AuctionOracleBase(const PointContainer_& _bidders, const PointContainer_& _items, const AuctionParams<Real>& params);
+ ~AuctionOracleBase() {}
+ Real get_epsilon() const { return epsilon; };
+ void set_epsilon(Real new_epsilon) { assert(new_epsilon >= 0.0); epsilon = new_epsilon; };
+ const std::vector<Real>& get_prices() const { return prices; }
+ virtual Real get_price(const size_t item_idx) const { return prices[item_idx]; } // TODO make virtual?
+//protected:
+ const PointContainer_& bidders;
+ const PointContainer_& items;
+ const size_t num_bidders_;
+ const size_t num_items_;
+ std::vector<Real> prices;
+ const Real wasserstein_power;
+ Real epsilon;
+ const Real internal_p;
+ unsigned int dim; // used only in pure geometric version, not for persistence diagrams
+ Real get_value_for_bidder(size_t bidder_idx, size_t item_idx) const;
+ Real get_value_for_diagonal_bidder(size_t item_idx) const;
+ Real get_cost_for_diagonal_bidder(size_t item_idx) const;
+};
+
+
+template<class Real>
+std::ostream& operator<< (std::ostream& output, const DebugOptimalBid<Real>& db);
+
+} // ws
+} // hera
+
+
+#include "auction_oracle_base.hpp"
+
+#endif
diff --git a/wasserstein/include/auction_oracle_base.hpp b/wasserstein/include/auction_oracle_base.hpp
new file mode 100644
index 0000000..b74c7fb
--- /dev/null
+++ b/wasserstein/include/auction_oracle_base.hpp
@@ -0,0 +1,97 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_ORACLE_BASE_HPP
+#define AUCTION_ORACLE_BASE_HPP
+
+#include <assert.h>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+#include "def_debug_ws.h"
+#include "auction_oracle.h"
+
+
+#ifdef FOR_R_TDA
+#undef DEBUG_AUCTION
+#endif
+
+namespace hera {
+namespace ws {
+
+template<class Real, class PointContainer>
+AuctionOracleBase<Real, PointContainer>::AuctionOracleBase(const PointContainer& _bidders,
+ const PointContainer& _items,
+ const AuctionParams<Real>& params) :
+ bidders(_bidders),
+ items(_items),
+ num_bidders_(_bidders.size()),
+ num_items_(_items.size()),
+ prices(items.size(), Real(0.0)),
+ wasserstein_power(params.wasserstein_power),
+ internal_p(params.internal_p),
+ dim(params.dim)
+{
+ assert(bidders.size() == items.size() );
+}
+
+
+template<class Real, class PointContainer>
+Real AuctionOracleBase<Real, PointContainer>::get_value_for_bidder(size_t bidder_idx, size_t item_idx) const
+{
+ return std::pow(dist_lp<Real>(bidders[bidder_idx], items[item_idx], internal_p, dim), wasserstein_power) + get_price(item_idx);
+}
+
+template<class Real, class PointContainer>
+Real AuctionOracleBase<Real, PointContainer>::get_value_for_diagonal_bidder(size_t item_idx) const
+{
+ return get_cost_for_diagonal_bidder(item_idx) + get_price(item_idx);
+}
+
+template<class Real, class PointContainer>
+Real AuctionOracleBase<Real, PointContainer>::get_cost_for_diagonal_bidder(size_t item_idx) const
+{
+ return std::pow(items[item_idx].persistence_lp(internal_p), wasserstein_power);
+}
+
+
+
+template<class Real>
+std::ostream& operator<< (std::ostream& output, const DebugOptimalBid<Real>& db)
+{
+ output << "best_item_value = " << db.best_item_value;
+ output << "; best_item_idx = " << db.best_item_idx;
+ output << "; second_best_item_value = " << db.second_best_item_value;
+ output << "; second_best_item_idx = " << db.second_best_item_idx;
+ return output;
+}
+
+} // ws
+} // hera
+
+#endif
diff --git a/wasserstein/include/auction_oracle_kdtree_pure_geom.h b/wasserstein/include/auction_oracle_kdtree_pure_geom.h
new file mode 100644
index 0000000..ebfab3b
--- /dev/null
+++ b/wasserstein/include/auction_oracle_kdtree_pure_geom.h
@@ -0,0 +1,94 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_ORACLE_KDTREE_PURE_GEOM_H
+#define AUCTION_ORACLE_KDTREE_PURE_GEOM_H
+
+
+#include <map>
+#include <memory>
+#include <set>
+
+#include <boost/range/adaptor/transformed.hpp>
+
+namespace ba = boost::adaptors;
+
+#include "basic_defs_ws.h"
+#include "auction_oracle_base.h"
+#include "dnn/geometry/euclidean-dynamic.h"
+#include "dnn/local/kd-tree.h"
+
+namespace hera
+{
+namespace ws
+{
+
+template <class Real_ = double, class PointContainer_ = hera::ws::dnn::DynamicPointVector<Real_>>
+struct AuctionOracleKDTreePureGeom : AuctionOracleBase<Real_, PointContainer_> {
+
+ using Real = Real_;
+ using DynamicPointTraitsR = typename hera::ws::dnn::DynamicPointTraits<Real>;
+ using DiagramPointR = typename DynamicPointTraitsR::PointType;
+ using PointHandleR = typename DynamicPointTraitsR::PointHandle;
+ using PointContainer = PointContainer_;
+ using DebugOptimalBidR = typename ws::DebugOptimalBid<Real>;
+
+ using DynamicPointTraits = hera::ws::dnn::DynamicPointTraits<Real>;
+ using KDTreeR = hera::ws::dnn::KDTree<DynamicPointTraits>;
+
+ AuctionOracleKDTreePureGeom(const PointContainer& bidders, const PointContainer& items, const AuctionParams<Real>& params);
+ ~AuctionOracleKDTreePureGeom();
+
+ // data members
+ // temporarily make everything public
+ DynamicPointTraits traits;
+ Real max_val_;
+ Real weight_adj_const_;
+ std::unique_ptr<KDTreeR> kdtree_;
+ std::vector<size_t> kdtree_items_;
+ // methods
+ void set_price(const IdxType items_idx, const Real new_price);
+ IdxValPair<Real> get_optimal_bid(const IdxType bidder_idx);
+ void adjust_prices();
+ void adjust_prices(const Real delta);
+
+ // debug routines
+ DebugOptimalBidR get_optimal_bid_debug(IdxType bidder_idx) const;
+ void sanity_check();
+
+ std::pair<Real, Real> get_minmax_price() const;
+
+};
+
+} // ws
+} // hera
+
+
+#include "auction_oracle_kdtree_pure_geom.hpp"
+
+#endif
diff --git a/wasserstein/include/auction_oracle_kdtree_pure_geom.hpp b/wasserstein/include/auction_oracle_kdtree_pure_geom.hpp
new file mode 100644
index 0000000..4ee7b45
--- /dev/null
+++ b/wasserstein/include/auction_oracle_kdtree_pure_geom.hpp
@@ -0,0 +1,225 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+#ifndef AUCTION_ORACLE_KDTREE_PURE_GEOM_HPP
+#define AUCTION_ORACLE_KDTREE_PURE_GEOM_HPP
+
+#include <assert.h>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+#include "def_debug_ws.h"
+#include "auction_oracle_kdtree_restricted.h"
+
+
+#ifdef FOR_R_TDA
+#undef DEBUG_AUCTION
+#endif
+
+namespace hera {
+namespace ws {
+
+
+// *****************************
+// AuctionOracleKDTreePureGeom
+// *****************************
+
+
+
+template <class Real_, class PointContainer_>
+std::ostream& operator<<(std::ostream& output, const AuctionOracleKDTreePureGeom<Real_, PointContainer_>& oracle)
+{
+ output << "Oracle " << &oracle << std::endl;
+ output << "max_val_ = " << oracle.max_val_ << "\n";
+ output << "prices = " << format_container_to_log(oracle.prices) << "\n";
+ output << "end of oracle " << &oracle << std::endl;
+ return output;
+}
+
+
+template<class Real_, class PointContainer_>
+AuctionOracleKDTreePureGeom<Real_, PointContainer_>::AuctionOracleKDTreePureGeom(const PointContainer_& _bidders,
+ const PointContainer_& _items,
+ const AuctionParams<Real_>& params) :
+ AuctionOracleBase<Real_, PointContainer_>(_bidders, _items, params),
+ traits(params.dim)
+{
+
+ traits.internal_p = params.internal_p;
+
+ std::vector<PointHandleR> item_handles(this->num_items_);
+ for(size_t i = 0; i < this->num_items_; ++i) {
+ item_handles[i] = traits.handle(this->items[i]);
+ }
+
+ //kdtree_ = std::unique_ptr<KDTreeR>(new KDTreeR(traits,
+ // this->items | ba::transformed([this](const DiagramPointR& p) { return traits.handle(p); }),
+ // params.wasserstein_power));
+
+ kdtree_ = std::unique_ptr<KDTreeR>(new KDTreeR(traits, item_handles, params.wasserstein_power));
+
+
+ max_val_ = 3*getFurthestDistance3Approx_pg(this->bidders, this->items, params.internal_p, params.dim);
+ max_val_ = std::pow(max_val_, params.wasserstein_power);
+ weight_adj_const_ = max_val_;
+}
+
+
+template<class Real_, class PointContainer_>
+typename AuctionOracleKDTreePureGeom<Real_, PointContainer_>::DebugOptimalBidR
+AuctionOracleKDTreePureGeom<Real_, PointContainer_>::get_optimal_bid_debug(IdxType bidder_idx) const
+{
+ auto bidder = this->bidders[bidder_idx];
+
+ size_t best_item_idx = k_invalid_index;
+ size_t second_best_item_idx = k_invalid_index;
+ Real best_item_value = std::numeric_limits<Real>::max();
+ Real second_best_item_value = std::numeric_limits<Real>::max();
+
+ for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ auto item = this->items[item_idx];
+ auto item_value = std::pow(traits.distance(bidder, item), this->wasserstein_power) + this->prices[item_idx];
+ if (item_value < best_item_value) {
+ best_item_value = item_value;
+ best_item_idx = item_idx;
+ }
+ }
+
+ assert(best_item_idx != k_invalid_index);
+
+ for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ auto item = this->items[item_idx];
+ if (item_idx == best_item_idx)
+ continue;
+
+ auto item_value = std::pow(traits.distance(bidder, item), this->wasserstein_power) + this->prices[item_idx];
+ if (item_value < second_best_item_value) {
+ second_best_item_value = item_value;
+ second_best_item_idx = item_idx;
+ }
+ }
+
+ assert(second_best_item_idx != k_invalid_index);
+ assert(second_best_item_value >= best_item_value);
+
+ DebugOptimalBidR result;
+
+ result.best_item_idx = best_item_idx;
+ result.best_item_value = best_item_value;
+ result.second_best_item_idx = second_best_item_idx;
+ result.second_best_item_value = second_best_item_value;
+
+ return result;
+}
+
+
+template<class Real_, class PointContainer_>
+IdxValPair<Real_> AuctionOracleKDTreePureGeom<Real_, PointContainer_>::get_optimal_bid(IdxType bidder_idx)
+{
+ auto two_best_items = kdtree_->findK(this->bidders[bidder_idx], 2);
+ size_t best_item_idx = traits.id(two_best_items[0].p);
+ Real best_item_value = two_best_items[0].d;
+ Real second_best_item_value = two_best_items[1].d;
+
+ IdxValPair<Real> result;
+
+ assert( second_best_item_value >= best_item_value );
+
+ result.first = best_item_idx;
+ result.second = ( second_best_item_value - best_item_value ) + this->prices[best_item_idx] + this->epsilon;
+
+#ifdef DEBUG_KDTREE_RESTR_ORACLE
+ auto bid_debug = get_optimal_bid_debug(bidder_idx);
+ assert(fabs(bid_debug.best_item_value - best_item_value) < 0.000000001);
+ assert(fabs(bid_debug.second_best_item_value - second_best_item_value) < 0.000000001);
+#endif
+
+ return result;
+}
+
+/*
+a_{ij} = d_{ij}
+value_{ij} = a_{ij} + price_j
+*/
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreePureGeom<Real_, PointContainer_>::set_price(IdxType item_idx,
+ Real new_price)
+{
+ assert(this->prices.size() == this->items.size());
+ // adjust_prices decreases prices,
+ // also this variable must be true in reverse phases of FR-auction
+
+ this->prices[item_idx] = new_price;
+ kdtree_->change_weight( traits.handle(this->items[item_idx]), new_price);
+}
+
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreePureGeom<Real_, PointContainer_>::adjust_prices(Real delta)
+{
+ if (delta == 0.0)
+ return;
+
+ for(auto& p : this->prices) {
+ p -= delta;
+ }
+
+ kdtree_->adjust_weights(delta);
+}
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreePureGeom<Real_, PointContainer_>::adjust_prices()
+{
+ auto pr_begin = this->prices.begin();
+ auto pr_end = this->prices.end();
+ Real min_price = *(std::min_element(pr_begin, pr_end));
+ adjust_prices(min_price);
+}
+
+template<class Real_, class PointContainer_>
+std::pair<Real_, Real_> AuctionOracleKDTreePureGeom<Real_, PointContainer_>::get_minmax_price() const
+{
+ auto r = std::minmax_element(this->prices.begin(), this->prices.end());
+ return std::make_pair(*r.first, *r.second);
+}
+
+template<class Real_, class PointContainer_>
+AuctionOracleKDTreePureGeom<Real_, PointContainer_>::~AuctionOracleKDTreePureGeom()
+{
+}
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreePureGeom<Real_, PointContainer_>::sanity_check()
+{
+}
+
+
+} // ws
+} // hera
+
+#endif
diff --git a/wasserstein/include/auction_oracle_kdtree_restricted.h b/wasserstein/include/auction_oracle_kdtree_restricted.h
new file mode 100644
index 0000000..b17089b
--- /dev/null
+++ b/wasserstein/include/auction_oracle_kdtree_restricted.h
@@ -0,0 +1,119 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_ORACLE_KDTREE_RESTRICTED_H
+#define AUCTION_ORACLE_KDTREE_RESTRICTED_H
+
+
+//#define USE_BOOST_HEAP
+
+#include <map>
+#include <memory>
+#include <set>
+
+
+#include "basic_defs_ws.h"
+#include "diagonal_heap.h"
+#include "auction_oracle_base.h"
+#include "dnn/geometry/euclidean-fixed.h"
+#include "dnn/local/kd-tree.h"
+
+namespace hera {
+namespace ws {
+
+template <class Real_ = double, class PointContainer_ = std::vector<DiagramPoint<Real_>>>
+struct AuctionOracleKDTreeRestricted : AuctionOracleBase<Real_, PointContainer_> {
+
+ using PointContainer = PointContainer_;
+ using Real = Real_;
+
+ using LossesHeapR = typename ws::LossesHeapOld<Real>;
+ using LossesHeapRHandle = typename ws::LossesHeapOld<Real>::handle_type;
+ using DiagramPointR = typename ws::DiagramPoint<Real>;
+ using DebugOptimalBidR = typename ws::DebugOptimalBid<Real>;
+
+ using DnnPoint = dnn::Point<2, Real>;
+ using DnnTraits = dnn::PointTraits<DnnPoint>;
+
+ AuctionOracleKDTreeRestricted(const PointContainer& bidders, const PointContainer& items, const AuctionParams<Real>& params);
+ ~AuctionOracleKDTreeRestricted();
+ // data members
+ // temporarily make everything public
+ Real max_val_;
+ Real weight_adj_const_;
+ dnn::KDTree<DnnTraits>* kdtree_;
+ std::vector<DnnPoint> dnn_points_;
+ std::vector<DnnPoint*> dnn_point_handles_;
+ LossesHeapR diag_items_heap_;
+ std::vector<LossesHeapRHandle> diag_heap_handles_;
+ std::vector<size_t> heap_handles_indices_;
+ std::vector<size_t> kdtree_items_;
+ std::vector<size_t> top_diag_indices_;
+ std::vector<size_t> top_diag_lookup_;
+ size_t top_diag_counter_ { 0 };
+ bool best_diagonal_items_computed_ { false };
+ Real best_diagonal_item_value_;
+ size_t second_best_diagonal_item_idx_ { k_invalid_index };
+ Real second_best_diagonal_item_value_ { std::numeric_limits<Real>::max() };
+
+
+ // methods
+ void set_price(const IdxType items_idx, const Real new_price, const bool update_diag = true);
+ IdxValPair<Real> get_optimal_bid(const IdxType bidder_idx);
+ void adjust_prices();
+ void adjust_prices(const Real delta);
+
+ // debug routines
+ DebugOptimalBidR get_optimal_bid_debug(IdxType bidder_idx) const;
+ void sanity_check();
+
+
+ // heap top vector
+ size_t get_heap_top_size() const;
+ void recompute_top_diag_items(bool hard = false);
+ void recompute_second_best_diag();
+ void reset_top_diag_counter();
+ void increment_top_diag_counter();
+ void add_top_diag_index(const size_t item_idx);
+ void remove_top_diag_index(const size_t item_idx);
+ bool is_in_top_diag_indices(const size_t item_idx) const;
+
+ std::pair<Real, Real> get_minmax_price() const;
+
+};
+
+template<class Real>
+std::ostream& operator<< (std::ostream& output, const DebugOptimalBid<Real>& db);
+
+} // ws
+} // hera
+
+
+#include "auction_oracle_kdtree_restricted.hpp"
+
+#endif
diff --git a/wasserstein/include/auction_oracle_kdtree_restricted.hpp b/wasserstein/include/auction_oracle_kdtree_restricted.hpp
new file mode 100644
index 0000000..f0e7ac6
--- /dev/null
+++ b/wasserstein/include/auction_oracle_kdtree_restricted.hpp
@@ -0,0 +1,538 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+#ifndef AUCTION_ORACLE_KDTREE_RESTRICTED_HPP
+#define AUCTION_ORACLE_KDTREE_RESTRICTED_HPP
+
+#include <assert.h>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+#include "def_debug_ws.h"
+#include "auction_oracle_kdtree_restricted.h"
+
+
+#ifdef FOR_R_TDA
+#undef DEBUG_AUCTION
+#endif
+
+namespace hera {
+namespace ws {
+
+
+// *****************************
+// AuctionOracleKDTreeRestricted
+// *****************************
+
+
+
+template <class Real_, class PointContainer_>
+std::ostream& operator<<(std::ostream& output, const AuctionOracleKDTreeRestricted<Real_, PointContainer_>& oracle)
+{
+ output << "Oracle " << &oracle << std::endl;
+ output << "max_val_ = " << oracle.max_val_ << ", ";
+ output << "best_diagonal_items_computed_ = " << oracle.best_diagonal_items_computed_ << ", ";
+ output << "best_diagonal_item_value_ = " << oracle.best_diagonal_item_value_ << ", ";
+ output << "second_best_diagonal_item_idx_ = " << oracle.second_best_diagonal_item_idx_ << ", ";
+ output << "second_best_diagonal_item_value_ = " << oracle.second_best_diagonal_item_value_ << ", ";
+ output << "prices = " << format_container_to_log(oracle.prices) << "\n";
+ output << "diag_items_heap_ = " << losses_heap_to_string(oracle.diag_items_heap_) << "\n";
+ output << "top_diag_indices_ = " << format_container_to_log(oracle.top_diag_indices_) << "\n";
+ output << "top_diag_counter_ = " << oracle.top_diag_counter_ << "\n";
+ output << "top_diag_lookup_ = " << format_container_to_log(oracle.top_diag_lookup_) << "\n";
+ output << "end of oracle " << &oracle << std::endl;
+ return output;
+}
+
+
+template<class Real_, class PointContainer_>
+AuctionOracleKDTreeRestricted<Real_, PointContainer_>::AuctionOracleKDTreeRestricted(const PointContainer_& _bidders,
+ const PointContainer_& _items,
+ const AuctionParams<Real>& params) :
+ AuctionOracleBase<Real>(_bidders, _items, params),
+ heap_handles_indices_(_items.size(), k_invalid_index),
+ kdtree_items_(_items.size(), k_invalid_index),
+ top_diag_lookup_(_items.size(), k_invalid_index)
+{
+ size_t dnn_item_idx { 0 };
+ size_t true_idx { 0 };
+ dnn_points_.clear();
+ dnn_points_.reserve(this->items.size());
+ // store normal items in kd-tree
+ for(const auto& g : this->items) {
+ if (g.is_normal() ) {
+ kdtree_items_[true_idx] = dnn_item_idx;
+ // index of items is id of dnn-point
+ DnnPoint p(true_idx);
+ p[0] = g.getRealX();
+ p[1] = g.getRealY();
+ dnn_points_.push_back(p);
+ assert(dnn_item_idx == dnn_points_.size() - 1);
+ dnn_item_idx++;
+ }
+ true_idx++;
+ }
+
+ assert(dnn_points_.size() < _items.size() );
+ for(size_t i = 0; i < dnn_points_.size(); ++i) {
+ dnn_point_handles_.push_back(&dnn_points_[i]);
+ }
+ DnnTraits traits;
+ traits.internal_p = params.internal_p;
+ kdtree_ = new dnn::KDTree<DnnTraits>(traits, dnn_point_handles_, params.wasserstein_power);
+
+ size_t handle_idx {0};
+ for(size_t item_idx = 0; item_idx < _items.size(); ++item_idx) {
+ if (this->items[item_idx].is_diagonal()) {
+ heap_handles_indices_[item_idx] = handle_idx++;
+ diag_heap_handles_.push_back(diag_items_heap_.push(std::make_pair(item_idx, 0.0)));
+ }
+ }
+ max_val_ = 3*getFurthestDistance3Approx<>(_bidders, _items, params.internal_p);
+ max_val_ = std::pow(max_val_, params.wasserstein_power);
+ weight_adj_const_ = max_val_;
+}
+
+
+template<class Real_, class PointContainer_>
+bool AuctionOracleKDTreeRestricted<Real_, PointContainer_>::is_in_top_diag_indices(const size_t item_idx) const
+{
+ return top_diag_lookup_[item_idx] != k_invalid_index;
+}
+
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeRestricted<Real_, PointContainer_>::add_top_diag_index(const size_t item_idx)
+{
+ assert(find(top_diag_indices_.begin(), top_diag_indices_.end(), item_idx) == top_diag_indices_.end());
+ assert(this->items[item_idx].is_diagonal());
+
+ top_diag_indices_.push_back(item_idx);
+ top_diag_lookup_[item_idx] = top_diag_indices_.size() - 1;
+}
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeRestricted<Real_, PointContainer_>::remove_top_diag_index(const size_t item_idx)
+{
+ if (top_diag_indices_.size() > 1) {
+ // remove item_idx from top_diag_indices after swapping
+ // it with the last element, update index lookup appropriately
+ auto old_index = top_diag_lookup_[item_idx];
+ auto end_element = top_diag_indices_.back();
+ std::swap(top_diag_indices_[old_index], top_diag_indices_.back());
+ top_diag_lookup_[end_element] = old_index;
+ }
+
+ top_diag_indices_.pop_back();
+ top_diag_lookup_[item_idx] = k_invalid_index;
+ if (top_diag_indices_.size() < 2) {
+ recompute_second_best_diag();
+ }
+ best_diagonal_items_computed_ = not top_diag_indices_.empty();
+ reset_top_diag_counter();
+}
+
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeRestricted<Real_, PointContainer_>::increment_top_diag_counter()
+{
+ assert(top_diag_counter_ >= 0 and top_diag_counter_ < top_diag_indices_.size());
+
+ ++top_diag_counter_;
+ if (top_diag_counter_ >= top_diag_indices_.size()) {
+ top_diag_counter_ -= top_diag_indices_.size();
+ }
+
+ assert(top_diag_counter_ >= 0 and top_diag_counter_ < top_diag_indices_.size());
+}
+
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeRestricted<Real_, PointContainer_>::reset_top_diag_counter()
+{
+ top_diag_counter_ = 0;
+}
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeRestricted<Real_, PointContainer_>::recompute_top_diag_items(bool hard)
+{
+ assert(hard or top_diag_indices_.empty());
+
+ if (hard) {
+ std::fill(top_diag_lookup_.begin(), top_diag_lookup_.end(), k_invalid_index);
+ top_diag_indices_.clear();
+ }
+
+ auto top_diag_iter = diag_items_heap_.ordered_begin();
+ best_diagonal_item_value_ = top_diag_iter->second;
+ add_top_diag_index(top_diag_iter->first);
+
+ ++top_diag_iter;
+
+ // traverse the heap while we see the same value
+ while(top_diag_iter != diag_items_heap_.ordered_end()) {
+ if ( top_diag_iter->second != best_diagonal_item_value_) {
+ break;
+ } else {
+ add_top_diag_index(top_diag_iter->first);
+ }
+ ++top_diag_iter;
+ }
+
+ recompute_second_best_diag();
+
+ best_diagonal_items_computed_ = true;
+ reset_top_diag_counter();
+}
+
+template<class Real_, class PointContainer_>
+typename AuctionOracleKDTreeRestricted<Real_, PointContainer_>::DebugOptimalBidR
+AuctionOracleKDTreeRestricted<Real_, PointContainer_>::get_optimal_bid_debug(IdxType bidder_idx) const
+{
+ auto bidder = this->bidders[bidder_idx];
+
+ size_t best_item_idx = k_invalid_index;
+ size_t second_best_item_idx = k_invalid_index;
+ Real best_item_value = std::numeric_limits<Real>::max();
+ Real second_best_item_value = std::numeric_limits<Real>::max();
+
+ for(IdxType item_idx = 0; item_idx < static_cast<IdxType>(this->items.size()); ++item_idx) {
+ auto item = this->items[item_idx];
+ if (item.type != bidder.type and item_idx != bidder_idx)
+ continue;
+ auto item_value = std::pow(dist_lp(bidder, item, this->internal_p, 2), this->wasserstein_power) + this->prices[item_idx];
+ if (item_value < best_item_value) {
+ best_item_value = item_value;
+ best_item_idx = item_idx;
+ }
+ }
+
+ assert(best_item_idx != k_invalid_index);
+
+ for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ auto item = this->items[item_idx];
+ if (item.type != bidder.type and static_cast<IdxType>(item_idx) != bidder_idx)
+ continue;
+ if (item_idx == best_item_idx)
+ continue;
+ auto item_value = std::pow(dist_lp(bidder, item, this->internal_p, 2), this->wasserstein_power) + this->prices[item_idx];
+ if (item_value < second_best_item_value) {
+ second_best_item_value = item_value;
+ second_best_item_idx = item_idx;
+ }
+ }
+
+ assert(second_best_item_idx != k_invalid_index);
+ assert(second_best_item_value >= best_item_value);
+
+ DebugOptimalBidR result;
+
+ result.best_item_idx = best_item_idx;
+ result.best_item_value = best_item_value;
+ result.second_best_item_idx = second_best_item_idx;
+ result.second_best_item_value = second_best_item_value;
+
+ return result;
+}
+
+
+template<class Real_, class PointContainer_>
+IdxValPair<Real_> AuctionOracleKDTreeRestricted<Real_, PointContainer_>::get_optimal_bid(IdxType bidder_idx)
+{
+ auto bidder = this->bidders[bidder_idx];
+
+ // corresponding point is always considered as a candidate
+ // if bidder is a diagonal point, proj_item is a normal point,
+ // and vice versa.
+
+ size_t best_item_idx { k_invalid_index };
+ size_t second_best_item_idx { k_invalid_index };
+ size_t best_diagonal_item_idx { k_invalid_index };
+ Real best_item_value;
+ Real second_best_item_value;
+
+
+ size_t proj_item_idx = bidder_idx;
+ assert( 0 <= proj_item_idx and proj_item_idx < this->items.size() );
+ assert(this->items[proj_item_idx].type != bidder.type);
+ Real proj_item_value = this->get_value_for_bidder(bidder_idx, proj_item_idx);
+
+ if (bidder.is_diagonal()) {
+ // for diagonal bidder the only normal point has already been added
+ // the other 2 candidates are diagonal items only, get from the heap
+ // with prices
+
+ if (not best_diagonal_items_computed_) {
+ recompute_top_diag_items();
+ }
+
+ best_diagonal_item_idx = top_diag_indices_[top_diag_counter_];
+ increment_top_diag_counter();
+
+ if ( proj_item_value < best_diagonal_item_value_) {
+ best_item_idx = proj_item_idx;
+ best_item_value = proj_item_value;
+ second_best_item_value = best_diagonal_item_value_;
+ second_best_item_idx = best_diagonal_item_idx;
+ } else if (proj_item_value < second_best_diagonal_item_value_) {
+ best_item_idx = best_diagonal_item_idx;
+ best_item_value = best_diagonal_item_value_;
+ second_best_item_value = proj_item_value;
+ second_best_item_idx = proj_item_idx;
+ } else {
+ best_item_idx = best_diagonal_item_idx;
+ best_item_value = best_diagonal_item_value_;
+ second_best_item_value = second_best_diagonal_item_value_;
+ second_best_item_idx = second_best_diagonal_item_idx_;
+ }
+ } else {
+ // for normal bidder get 2 best items among non-diagonal points from
+ // kdtree_
+ DnnPoint bidder_dnn;
+ bidder_dnn[0] = bidder.getRealX();
+ bidder_dnn[1] = bidder.getRealY();
+ auto two_best_items = kdtree_->findK(bidder_dnn, 2);
+ size_t best_normal_item_idx { two_best_items[0].p->id() };
+ Real best_normal_item_value { two_best_items[0].d };
+ // if there is only one off-diagonal point in the second diagram,
+ // kd-tree will not return the second candidate.
+ // Set its value to inf, so it will always lose to the value of the projection
+ Real second_best_normal_item_value { two_best_items.size() == 1 ? std::numeric_limits<Real>::max() : two_best_items[1].d };
+
+ if ( proj_item_value < best_normal_item_value) {
+ best_item_idx = proj_item_idx;
+ best_item_value = proj_item_value;
+ second_best_item_value = best_normal_item_value;
+ } else if (proj_item_value < second_best_normal_item_value) {
+ best_item_idx = best_normal_item_idx;
+ best_item_value = best_normal_item_value;
+ second_best_item_value = proj_item_value;
+ } else {
+ best_item_idx = best_normal_item_idx;
+ best_item_value = best_normal_item_value;
+ second_best_item_value = second_best_normal_item_value;
+ }
+ }
+
+ IdxValPair<Real> result;
+
+ assert( second_best_item_value >= best_item_value );
+
+ result.first = best_item_idx;
+ result.second = ( second_best_item_value - best_item_value ) + this->prices[best_item_idx] + this->epsilon;
+
+#ifdef DEBUG_KDTREE_RESTR_ORACLE
+ auto db = get_optimal_bid_debug(bidder_idx);
+ assert(fabs(db.best_item_value - best_item_value) < 0.000001);
+ assert(fabs(db.second_best_item_value - second_best_item_value) < 0.000001);
+ //std::cout << "bid OK" << std::endl;
+#endif
+
+ return result;
+}
+/*
+a_{ij} = d_{ij}
+value_{ij} = a_{ij} + price_j
+*/
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeRestricted<Real_, PointContainer_>::recompute_second_best_diag()
+{
+ if (top_diag_indices_.size() > 1) {
+ second_best_diagonal_item_value_ = best_diagonal_item_value_;
+ second_best_diagonal_item_idx_ = top_diag_indices_[0];
+ } else {
+ if (diag_items_heap_.size() == 1) {
+ second_best_diagonal_item_value_ = std::numeric_limits<Real>::max();
+ second_best_diagonal_item_idx_ = k_invalid_index;
+ } else {
+ auto diag_iter = diag_items_heap_.ordered_begin();
+ ++diag_iter;
+ second_best_diagonal_item_value_ = diag_iter->second;
+ second_best_diagonal_item_idx_ = diag_iter->first;
+ }
+ }
+}
+
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeRestricted<Real_, PointContainer_>::set_price(IdxType item_idx,
+ Real new_price,
+ const bool update_diag)
+{
+ assert(this->prices.size() == this->items.size());
+ assert( 0 < diag_heap_handles_.size() and diag_heap_handles_.size() <= this->items.size());
+ // adjust_prices decreases prices,
+ // also this variable must be true in reverse phases of FR-auction
+ bool item_goes_down = new_price > this->prices[item_idx];
+
+ this->prices[item_idx] = new_price;
+ if ( this->items[item_idx].is_normal() ) {
+ assert(0 <= item_idx and item_idx < static_cast<IdxType>(kdtree_items_.size()));
+ assert(0 <= kdtree_items_[item_idx] and kdtree_items_[item_idx] < dnn_point_handles_.size());
+ kdtree_->change_weight( dnn_point_handles_[kdtree_items_[item_idx]], new_price);
+ } else {
+ assert(diag_heap_handles_.size() > heap_handles_indices_.at(item_idx));
+ if (item_goes_down) {
+ diag_items_heap_.decrease(diag_heap_handles_[heap_handles_indices_[item_idx]], std::make_pair(item_idx, new_price));
+ } else {
+ diag_items_heap_.increase(diag_heap_handles_[heap_handles_indices_[item_idx]], std::make_pair(item_idx, new_price));
+ }
+ if (update_diag) {
+ // Update top_diag_indices_ only if necessary:
+ // normal bidders take their projections, which might not be on top
+ // also, set_price is called by adjust_prices, and we may have already
+ // removed the item from top_diag
+ if (is_in_top_diag_indices(item_idx)) {
+ remove_top_diag_index(item_idx);
+ }
+
+ if (item_idx == (IdxType)second_best_diagonal_item_idx_) {
+ recompute_second_best_diag();
+ }
+ }
+ }
+}
+
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeRestricted<Real_, PointContainer_>::adjust_prices(Real delta)
+{
+ if (delta == 0.0)
+ return;
+
+ for(auto& p : this->prices) {
+ p -= delta;
+ }
+
+ kdtree_->adjust_weights(delta);
+
+ bool price_goes_up = delta < 0;
+
+ for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ if (this->items[item_idx].is_diagonal()) {
+ auto new_price = this->prices[item_idx];
+ if (price_goes_up) {
+ diag_items_heap_.decrease(diag_heap_handles_[heap_handles_indices_[item_idx]], std::make_pair(item_idx, new_price));
+ } else {
+ diag_items_heap_.increase(diag_heap_handles_[heap_handles_indices_[item_idx]], std::make_pair(item_idx, new_price));
+ }
+ }
+ }
+ best_diagonal_item_value_ -= delta;
+ second_best_diagonal_item_value_ -= delta;
+}
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeRestricted<Real_, PointContainer_>::adjust_prices()
+{
+ auto pr_begin = this->prices.begin();
+ auto pr_end = this->prices.end();
+ Real min_price = *(std::min_element(pr_begin, pr_end));
+ adjust_prices(min_price);
+}
+
+template<class Real_, class PointContainer_>
+size_t AuctionOracleKDTreeRestricted<Real_, PointContainer_>::get_heap_top_size() const
+{
+ return top_diag_indices_.size();
+}
+
+template<class Real_, class PointContainer_>
+std::pair<Real_, Real_> AuctionOracleKDTreeRestricted<Real_, PointContainer_>::get_minmax_price() const
+{
+ auto r = std::minmax_element(this->prices.begin(), this->prices.end());
+ return std::make_pair(*r.first, *r.second);
+}
+
+
+
+template<class Real_, class PointContainer_>
+AuctionOracleKDTreeRestricted<Real_, PointContainer_>::~AuctionOracleKDTreeRestricted()
+{
+ delete kdtree_;
+}
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeRestricted<Real_, PointContainer_>::sanity_check()
+{
+#ifdef DEBUG_KDTREE_RESTR_ORACLE
+ if (best_diagonal_items_computed_) {
+ std::vector<Real> diag_items_price_vec;
+ diag_items_price_vec.reserve(this->items.size());
+
+ for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ if (this->items.at(item_idx).is_diagonal()) {
+ diag_items_price_vec.push_back(this->prices.at(item_idx));
+ } else {
+ diag_items_price_vec.push_back(std::numeric_limits<Real>::max());
+ }
+ }
+
+ auto best_iter = std::min_element(diag_items_price_vec.begin(), diag_items_price_vec.end());
+ assert(best_iter != diag_items_price_vec.end());
+ Real true_best_diag_value = *best_iter;
+ size_t true_best_diag_idx = best_iter - diag_items_price_vec.begin();
+ assert(true_best_diag_value != std::numeric_limits<Real>::max());
+
+ Real true_second_best_diag_value = std::numeric_limits<Real>::max();
+ size_t true_second_best_diag_idx = k_invalid_index;
+ for(size_t item_idx = 0; item_idx < diag_items_price_vec.size(); ++item_idx) {
+ if (this->items.at(item_idx).is_normal()) {
+ assert(top_diag_lookup_.at(item_idx) == k_invalid_index);
+ continue;
+ }
+
+ auto i_iter = std::find(top_diag_indices_.begin(), top_diag_indices_.end(), item_idx);
+ if (diag_items_price_vec.at(item_idx) == true_best_diag_value) {
+ assert(i_iter != top_diag_indices_.end());
+ assert(top_diag_lookup_.at(item_idx) == i_iter - top_diag_indices_.begin());
+ } else {
+ assert(top_diag_lookup_.at(item_idx) == k_invalid_index);
+ assert(i_iter == top_diag_indices_.end());
+ }
+
+ if (item_idx == true_best_diag_idx) {
+ continue;
+ }
+ if (diag_items_price_vec.at(item_idx) < true_second_best_diag_value) {
+ true_second_best_diag_value = diag_items_price_vec.at(item_idx);
+ true_second_best_diag_idx = item_idx;
+ }
+ }
+
+ assert(true_best_diag_value == best_diagonal_item_value_);
+ assert(true_second_best_diag_idx != k_invalid_index);
+ assert(true_second_best_diag_value == second_best_diagonal_item_value_);
+ }
+#endif
+}
+
+
+} // ws
+} // hera
+
+#endif
diff --git a/wasserstein/include/auction_oracle_kdtree_single_diag.h b/wasserstein/include/auction_oracle_kdtree_single_diag.h
new file mode 100644
index 0000000..9192993
--- /dev/null
+++ b/wasserstein/include/auction_oracle_kdtree_single_diag.h
@@ -0,0 +1,219 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_ORACLE_KDTREE_SINGLE_DIAG_H
+#define AUCTION_ORACLE_KDTREE_SINGLE_DIAG_H
+
+
+#include <map>
+#include <memory>
+#include <set>
+#include <list>
+#include <ostream>
+
+#include "basic_defs_ws.h"
+#include "dnn/geometry/euclidean-fixed.h"
+#include "dnn/local/kd-tree.h"
+
+namespace hera {
+namespace ws {
+
+
+template <class Real = double>
+struct ItemSlice;
+
+template <class Real = double>
+bool operator<(const ItemSlice<Real>& s_1, const ItemSlice<Real>& s_2);
+
+template <class Real = double>
+bool operator>(const ItemSlice<Real>& s_1, const ItemSlice<Real>& s_2);
+
+template <class Real>
+struct ItemSlice {
+public:
+ using RealType = Real;
+
+ size_t item_idx;
+ Real loss;
+ ItemSlice(size_t _item_idx, const Real _loss);
+
+ void set_loss(const Real new_loss) { loss = new_loss; }
+ void adjust_loss(const Real delta) { loss -= delta; }
+
+ friend bool operator< <>(const ItemSlice<Real>&, const ItemSlice<Real>&);
+ friend bool operator> <>(const ItemSlice<Real>&, const ItemSlice<Real>&);
+
+private:
+};
+
+
+template <class Real = double>
+class LossesHeap {
+public:
+ using ItemSliceR = ItemSlice<Real>;
+ using KeeperTypeR = std::set<ItemSliceR, std::less<ItemSliceR> >;
+ using IterTypeR = typename KeeperTypeR::iterator;
+
+ LossesHeap() {}
+ LossesHeap(const std::vector<ItemSliceR>&);
+ void adjust_prices(const Real delta); // subtract delta from all values
+ ItemSliceR get_best_slice() const;
+ ItemSliceR get_second_best_slice() const;
+
+ template<typename ...Args>
+ decltype(auto) emplace(Args&&... args)
+ {
+ return keeper.emplace(std::forward<Args>(args)...);
+ }
+
+
+ IterTypeR begin() { return keeper.begin(); }
+ IterTypeR end() { return keeper.end(); }
+ void erase(IterTypeR iter) { assert(iter != keeper.end()); keeper.erase(iter); }
+ decltype(auto) insert(const ItemSliceR& item) { return keeper.insert(item); }
+ size_t size() const { return keeper.size(); }
+ bool empty() const { return keeper.empty(); }
+//private:
+ std::set<ItemSliceR, std::less<ItemSliceR> > keeper;
+};
+
+template <class Real>
+struct DiagonalBid {
+ DiagonalBid() {}
+
+ std::vector<size_t> assigned_normal_items;
+ std::vector<Real> assigned_normal_items_bid_values;
+
+ std::vector<size_t> best_item_indices;
+ std::vector<Real> bid_values;
+
+ // common bid value for diag-diag
+ Real diag_to_diag_value { 0.0 };
+
+ // analogous to second best item value; denoted by w in Bertsekas's paper on auction for transportation problem
+ Real almost_best_value { 0.0 };
+
+ // how many points to get from unassigned diagonal chunk
+ int num_from_unassigned_diag { 0 };
+};
+
+template <class Real_ = double, class PointContainer_ = std::vector<DiagramPoint<Real_>>>
+struct AuctionOracleKDTreeSingleDiag : AuctionOracleBase<Real_, PointContainer_> {
+
+ using PointContainer = PointContainer_;
+ using Real = Real_;
+
+ using DnnPoint = dnn::Point<2, Real>;
+ using DnnTraits = dnn::PointTraits<DnnPoint>;
+
+ using IdxValPairR = typename ws::IdxValPair<Real>;
+ using ItemSliceR = typename ws::ItemSlice<Real>;
+ using LossesHeapR = typename ws::LossesHeap<Real>;
+ using LossesHeapIterR = typename ws::LossesHeap<Real>::IterTypeR;
+ using DiagramPointR = typename ws::DiagramPoint<Real>;
+ using DiagonalBidR = typename ws::DiagonalBid<Real>;
+
+ AuctionOracleKDTreeSingleDiag(const PointContainer& bidders,
+ const PointContainer& items,
+ const AuctionParams<Real>& params);
+ ~AuctionOracleKDTreeSingleDiag();
+ // data members
+ // temporarily make everything public
+ Real max_val_;
+ size_t num_diag_items_;
+ size_t num_normal_items_;
+ size_t num_diag_bidders_;
+ size_t num_normal_bidders_;
+ dnn::KDTree<DnnTraits>* kdtree_;
+ std::vector<DnnPoint> dnn_points_;
+ std::vector<DnnPoint*> dnn_point_handles_;
+ std::vector<size_t> kdtree__items_;
+
+ // this heap is used by off-diagonal bidders to get the cheapest diagonal
+ // item; index in the IdxVal is a valid item index in the vector of items
+ // items in diag_assigned_to_diag_slice_ and in diag_unassigned_slice_
+ // are not stored in this heap
+ LossesHeapR diag_items_heap_;
+ // vector of iterators; if item_idx is in diag_assigned_to_diag_slice_ or
+ // in diag_unassigned_slice_, then diag_items_heap__iters_[item_idx] ==
+ // diag_items_heap_.end()
+ std::vector<LossesHeapIterR> diag_items_heap__iters_;
+
+
+ // this heap is used by _the_ diagonal bidder to get the cheapest items
+ // * value in IdxValPair is price + persistence (i.e., price for
+ // diagonal items)
+ // * index in IdxValPair is a valid item index in the vector of items
+ // items in diag_assigned_to_diag_slice_ and in diag_unassigned_slice_
+ // are not stored in this heap
+ LossesHeapR all_items_heap_;
+ std::vector<LossesHeapIterR> all_items_heap__iters_;
+
+ std::unordered_set<size_t> diag_assigned_to_diag_slice_;
+ std::unordered_set<size_t> diag_unassigned_slice_;
+
+
+ std::unordered_set<size_t> normal_items_assigned_to_diag_;
+
+ Real diag_to_diag_price_;
+ Real diag_unassigned_price_;
+
+ // methods
+ Real get_price(const size_t item_idx) const override;
+ void set_price(const size_t item_idx,
+ const Real new_price,
+ const bool item_is_diagonal,
+ const bool bidder_is_diagonal,
+ const OwnerType old_owner_type);
+
+ IdxValPair<Real> get_optimal_bid(const IdxType bidder_idx);
+
+ DiagonalBidR get_optimal_bids_for_diagonal(int unassigned_mass);
+ void process_unassigned_diagonal(const int unassigned_mass,
+ int& accumulated_mass,
+ bool& saw_diagonal_slice,
+ int& num_classes,
+ Real& w,
+ DiagonalBidR& result,
+ bool& found_w);
+
+ void adjust_prices();
+ void flush_assignment();
+ void sanity_check();
+
+ bool is_item_diagonal(const size_t item_idx) const;
+ bool is_item_normal(const size_t item_idx) const { return not is_item_diagonal(item_idx); }
+
+};
+
+} // ws
+} // hera
+
+#include "auction_oracle_kdtree_single_diag.hpp"
+
+#endif
diff --git a/wasserstein/include/auction_oracle_kdtree_single_diag.hpp b/wasserstein/include/auction_oracle_kdtree_single_diag.hpp
new file mode 100644
index 0000000..42677ab
--- /dev/null
+++ b/wasserstein/include/auction_oracle_kdtree_single_diag.hpp
@@ -0,0 +1,717 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+#ifndef AUCTION_ORACLE_KDTREE_RESTRICTED_SINGLE_DIAG_HPP
+#define AUCTION_ORACLE_KDTREE_RESTRICTED_SINGLE_DIAG_HPP
+
+#include <assert.h>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+#include "def_debug_ws.h"
+#include "auction_oracle.h"
+
+
+#ifdef FOR_R_TDA
+#undef DEBUG_AUCTION
+#endif
+
+namespace hera {
+namespace ws {
+
+// *****************************
+// AuctionOracleKDTreeSingleDiag
+// *****************************
+
+
+
+template <class Real>
+ItemSlice<Real>::ItemSlice(size_t _item_idx,
+ const Real _loss) :
+ item_idx(_item_idx),
+ loss(_loss)
+{
+}
+
+
+template <class Real>
+bool operator<(const ItemSlice<Real>& s_1, const ItemSlice<Real>& s_2)
+{
+ return s_1.loss < s_2.loss
+ or (s_1.loss == s_2.loss and s_1.item_idx < s_2.item_idx);
+}
+
+template <class Real>
+bool operator>(const ItemSlice<Real>& s_1, const ItemSlice<Real>& s_2)
+{
+ return s_1.loss > s_2.loss
+ or (s_1.loss == s_2.loss and s_1.item_idx > s_2.item_idx);
+}
+
+template<class Real>
+std::ostream& operator<<(std::ostream& s, const ItemSlice<Real>& x)
+{
+ s << "(" << x.item_idx << ", " << x.loss << ")";
+ return s;
+}
+
+// *****************************
+// LossesHeap
+// *****************************
+
+
+template <class Real>
+void LossesHeap<Real>::adjust_prices(const Real delta)
+{
+ throw std::runtime_error("not implemented");
+}
+
+template <class Real>
+typename LossesHeap<Real>::ItemSliceR LossesHeap<Real>::get_best_slice() const
+{
+ return *(keeper.begin());
+}
+
+template <class Real>
+typename LossesHeap<Real>::ItemSliceR LossesHeap<Real>::get_second_best_slice() const
+{
+ if (keeper.size() > 1) {
+ return *std::next(keeper.begin());
+ } else {
+ return ItemSliceR(k_invalid_index, std::numeric_limits<Real>::max());
+ }
+}
+
+template<class Real>
+std::ostream& operator<<(std::ostream& s, const LossesHeap<Real>& x)
+{
+ s << "Heap[ ";
+ for(auto iter = x.keeper.begin(); iter != x.keeper.end(); ++iter) {
+ s << *iter << "\n";
+ }
+ s << "]\n";
+ return s;
+}
+
+// *****************************
+// DiagonalBid
+// *****************************
+
+template <class Real>
+std::ostream& operator<<(std::ostream& s, const DiagonalBid<Real>& b)
+{
+ s << "DiagonalBid { num_from_unassigned_diag = " << b.num_from_unassigned_diag;
+ s << ", diag_to_diag_value = " << b.diag_to_diag_value;
+ s << ", almost_best_value = " << b.almost_best_value;
+ s << ",\nbest_item_indices = [";
+ for(const auto i : b.best_item_indices) {
+ s << i << ", ";
+ }
+ s << "]\n";
+
+ s << ",\nbid_values= [";
+ for(const auto v : b.bid_values) {
+ s << v << ", ";
+ }
+ s << "]\n";
+
+ s << ",\nassigned_normal_items= [";
+ for(const auto i : b.assigned_normal_items) {
+ s << i << ", ";
+ }
+ s << "]\n";
+
+ s << ",\nassigned_normal_items_bid_values = [";
+ for(const auto v : b.assigned_normal_items_bid_values) {
+ s << v << ", ";
+ }
+ s << "]\n";
+
+ return s;
+}
+
+// *****************************
+// AuctionOracleKDTreeSingleDiag
+// *****************************
+
+template<class Real_, class PointContainer_>
+std::ostream& operator<<(std::ostream& s, const AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>& x)
+{
+ s << "oracle: bidders" << std::endl;
+ for(const auto& p : x.bidders) {
+ s << p << "\n";
+ }
+ s << "items:";
+
+ for(const auto& p : x.items) {
+ s << p << "\n";
+ }
+
+ s << "diag_unassigned_slice_.size = " << x.diag_unassigned_slice_.size() << ", ";
+ s << "diag_unassigned_price_ = " << x.diag_unassigned_price_ << ", ";
+ s << "diag unassigned slice [";
+
+ for(const auto& i : x.diag_unassigned_slice_) {
+ s << i << ", ";
+ }
+ s << "]\n ";
+
+ s << "diag_assigned_to_diag_slice_.size = " << x.diag_assigned_to_diag_slice_.size() << ", ";
+ s << "diag_assigned_to_diag_price = " << x.diag_to_diag_price_ << "\n";
+ s << "diag_assigned_to_diag_slice_ [";
+
+ for(const auto& i : x.diag_assigned_to_diag_slice_) {
+ s << i << ", ";
+ }
+ s << "]\n ";
+
+ s << "diag_items_heap_.size = " << x.diag_items_heap_.size() << "\n ";
+ s << x.diag_items_heap_;
+
+ s << "all_items_heap_.size = " << x.all_items_heap_.size() << "\n ";
+ s << x.all_items_heap_;
+
+ s << "epsilon = " << x.epsilon << std::endl;
+
+ return s;
+}
+
+
+template<class Real_, class PointContainer_>
+AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::AuctionOracleKDTreeSingleDiag(const PointContainer_& _bidders,
+ const PointContainer_& _items,
+ const AuctionParams<Real>& params) :
+ AuctionOracleBase<Real_, PointContainer_>(_bidders, _items, params),
+ max_val_(std::pow( 3.0 * getFurthestDistance3Approx<>(_bidders, _items, params.internal_p), params.wasserstein_power)),
+ num_diag_items_(0),
+ kdtree__items_(_items.size(), k_invalid_index)
+{
+ size_t dnn_item_idx { 0 };
+ dnn_points_.clear();
+
+ all_items_heap__iters_.clear();
+ all_items_heap__iters_.reserve( 4 * _items.size() / 7);
+
+
+ for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ const auto& item = this->items[item_idx];
+ if (item.is_normal() ) {
+ // store normal items in kd-tree
+ kdtree__items_[item_idx] = dnn_item_idx;
+ // index of items is id of dnn-point
+ DnnPoint p(item_idx);
+ p[0] = item.x;
+ p[1] = item.y;
+ dnn_points_.push_back(p);
+ assert(dnn_item_idx == dnn_points_.size() - 1);
+ dnn_item_idx++;
+ // add slice to vector
+ auto ins_res = all_items_heap_.emplace(item_idx, this->get_value_for_diagonal_bidder(item_idx));
+ all_items_heap__iters_.push_back(ins_res.first);
+ assert(ins_res.second);
+ } else {
+ // all diagonal items are initially in the unassigned slice
+ diag_unassigned_slice_.insert(item_idx);
+ all_items_heap__iters_.push_back(all_items_heap_.end());
+ diag_items_heap__iters_.push_back(diag_items_heap_.end());
+ ++num_diag_items_;
+ }
+ }
+
+ num_normal_items_ = this->items.size() - num_diag_items_;
+ num_normal_bidders_ = num_diag_items_;
+ num_diag_bidders_ = this->bidders.size() - num_normal_bidders_;
+
+ assert(dnn_points_.size() < _items.size() );
+ for(size_t i = 0; i < dnn_points_.size(); ++i) {
+ dnn_point_handles_.push_back(&dnn_points_[i]);
+ }
+
+ DnnTraits traits;
+ traits.internal_p = params.internal_p;
+
+ kdtree_ = new dnn::KDTree<DnnTraits>(traits, dnn_point_handles_, this->wasserstein_power);
+
+ sanity_check();
+
+ //std::cout << "IN CTOR: " << *this << std::endl;
+
+}
+
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::process_unassigned_diagonal(const int unassigned_mass, int& accumulated_mass, bool& saw_diagonal_slice, int& num_classes, Real& w, DiagonalBidR& result, bool& found_w)
+{
+ result.num_from_unassigned_diag = std::min(static_cast<int>(diag_unassigned_slice_.size()), static_cast<int>(unassigned_mass - accumulated_mass));
+ if (not saw_diagonal_slice) {
+ saw_diagonal_slice = true;
+ ++num_classes;
+ }
+
+ accumulated_mass += result.num_from_unassigned_diag;
+ //std::cout << "got mass from diagunassigned_slice, result.num_from_unassigned_diag = " << result.num_from_unassigned_diag << ", accumulated_mass = " << accumulated_mass << std::endl;
+
+ if (static_cast<int>(diag_unassigned_slice_.size()) > result.num_from_unassigned_diag and num_classes >= 2) {
+ found_w = true;
+ w = diag_unassigned_price_;
+ //std::cout << "w found from diag_unassigned_slice_, too, w = " << w << std::endl;
+ result.almost_best_value = w;
+ }
+
+}
+
+
+template<class Real_, class PointContainer_>
+typename AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::DiagonalBidR AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::get_optimal_bids_for_diagonal(int unassigned_mass)
+{
+ sanity_check();
+
+ assert(unassigned_mass == static_cast<decltype(unassigned_mass)>(num_diag_bidders_)
+ - static_cast<decltype(unassigned_mass)>(normal_items_assigned_to_diag_.size())
+ - static_cast<decltype(unassigned_mass)>(diag_assigned_to_diag_slice_.size()) );
+ assert(unassigned_mass > 0);
+
+ DiagonalBidR result;
+
+
+ // number of similarity classes already assigned to diagonal bidder
+ // each normal point is a single class
+ // all diagonal points are in one class
+ int num_classes = normal_items_assigned_to_diag_.size() + ( diag_assigned_to_diag_slice_.empty() ? 0 : 1 );
+ bool saw_diagonal_slice = not diag_assigned_to_diag_slice_.empty();
+ bool found_w = false;
+
+ //std::cout << "Enter get_optimal_bids_for_diagonal, unassigned_mass = " << unassigned_mass <<", num_classes = " << num_classes << ", saw_diagonal_slice = " << std::boolalpha << saw_diagonal_slice << std::endl;
+
+ decltype(unassigned_mass) accumulated_mass = 0;
+
+
+ Real w { std::numeric_limits<Real>::max() };
+ bool unassigned_not_processed = not diag_unassigned_slice_.empty();
+
+ for(auto slice_iter = all_items_heap_.begin(); slice_iter != all_items_heap_.end(); ++slice_iter) {
+
+ auto slice = *slice_iter;
+
+ if ( is_item_normal(slice.item_idx) and normal_items_assigned_to_diag_.count(slice.item_idx) == 1) {
+ //std::cout << __LINE__ << ": skipping slice " << slice << std::endl;
+ // this item is already assigned to diagonal bidder, skip
+ continue;
+ }
+
+ if (unassigned_not_processed and slice.loss >= diag_unassigned_price_) {
+ // diag_unassigned slice is better,
+ // process it first
+ process_unassigned_diagonal(unassigned_mass, accumulated_mass, saw_diagonal_slice, num_classes, w, result, found_w);
+ unassigned_not_processed = false;
+ if (accumulated_mass >= unassigned_mass and found_w) {
+ break;
+ }
+ }
+
+
+ if (is_item_normal(slice.item_idx)) {
+ // all off-diagonal items are distinct
+ ++num_classes;
+ } else if (not saw_diagonal_slice) {
+ saw_diagonal_slice = true;
+ ++num_classes;
+ }
+
+ if (accumulated_mass < unassigned_mass) {
+ //std::cout << __LINE__ << ": added slice to best items " << slice << std::endl;
+ result.best_item_indices.push_back(slice.item_idx);
+ }
+
+ if (accumulated_mass >= unassigned_mass and num_classes >= 2) {
+ //std::cout << "Found w, slice = " << slice << std::endl;
+ w = slice.loss;
+ found_w = true;
+ result.almost_best_value = w;
+ break;
+ }
+
+ // all items in all_items heap have mass 1
+ ++accumulated_mass;
+ //std::cout << "accumulated_mass = " << accumulated_mass << std::endl;
+
+ }
+
+ if (unassigned_not_processed and (accumulated_mass < unassigned_mass or not found_w)) {
+ process_unassigned_diagonal(unassigned_mass, accumulated_mass, saw_diagonal_slice, num_classes, w, result, found_w);
+ }
+
+ assert(found_w);
+
+ //if (w == std::numeric_limits<Real>::max()) { std::cout << "HERE: " << *this << std::endl; }
+ assert(w != std::numeric_limits<Real>::max());
+
+ result.assigned_normal_items.clear();
+ result.assigned_normal_items_bid_values.clear();
+
+ result.assigned_normal_items.reserve(normal_items_assigned_to_diag_.size());
+ result.assigned_normal_items_bid_values.reserve(normal_items_assigned_to_diag_.size());
+
+ // add already assigned normal items and their new prices to bid
+ for(const auto item_idx : normal_items_assigned_to_diag_) {
+ assert( all_items_heap__iters_[item_idx] != all_items_heap_.end() );
+ assert( is_item_normal(item_idx) );
+
+ result.assigned_normal_items.push_back(item_idx);
+ Real bid_value = w - this->get_cost_for_diagonal_bidder(item_idx) + this->epsilon;
+ //if ( bid_value <= this->get_price(item_idx) ) {
+ //std::cout << bid_value << " vs price " << this->get_price(item_idx) << std::endl;
+ //std::cout << *this << std::endl;
+ //}
+ assert( bid_value >= this->get_price(item_idx) );
+ result.assigned_normal_items_bid_values.push_back(bid_value);
+ }
+
+ // calculate bid values
+ // diag-to-diag items all have the same bid value
+ if (saw_diagonal_slice) {
+ result.diag_to_diag_value = w + this->epsilon;
+ } else {
+ result.diag_to_diag_value = std::numeric_limits<Real>::max();
+ }
+
+ result.bid_values.reserve(result.best_item_indices.size());
+ for(const auto item_idx : result.best_item_indices) {
+ Real bid_value = w - this->get_cost_for_diagonal_bidder(item_idx) + this->epsilon;
+ result.bid_values.push_back(bid_value);
+ }
+
+ return result;
+}
+
+
+template<class Real_, class PointContainer_>
+IdxValPair<Real_> AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::get_optimal_bid(IdxType bidder_idx)
+{
+ //std::cout << "enter get_optimal_bid" << std::endl;
+ sanity_check();
+
+ auto bidder = this->bidders[bidder_idx];
+
+ size_t best_item_idx;
+ Real best_item_price;
+ Real best_item_value;
+ Real second_best_item_value;
+
+ // this function is for normal bidders only
+ assert(bidder.is_normal());
+
+
+ // get 2 best items among non-diagonal points from kdtree_
+ DnnPoint bidder_dnn;
+ bidder_dnn[0] = bidder.getRealX();
+ bidder_dnn[1] = bidder.getRealY();
+ auto two_best_items = kdtree_->findK(bidder_dnn, 2);
+ size_t best_normal_item_idx { two_best_items[0].p->id() };
+ Real best_normal_item_value { two_best_items[0].d };
+ // if there is only one off-diagonal point in the second diagram,
+ // kd-tree will not return the second candidate.
+ // Set its price to inf, so it will always lose to the price of the projection
+ Real second_best_normal_item_value { two_best_items.size() == 1 ? std::numeric_limits<Real>::max() : two_best_items[1].d };
+
+ size_t best_diag_item_idx;
+ Real best_diag_value;
+ Real best_diag_price;
+
+ {
+ Real diag_edge_cost = std::pow(bidder.persistence_lp(this->internal_p), this->wasserstein_power);
+ auto best_diag_price_in_heap = diag_items_heap_.empty() ? std::numeric_limits<Real>::max() : diag_items_heap_.get_best_slice().loss;
+ auto best_diag_idx_in_heap = diag_items_heap_.empty() ? k_invalid_index : diag_items_heap_.get_best_slice().item_idx;
+ // if unassigned_diag_slice is empty, its price is max,
+ // same for diag-diag assigned slice, so the ifs below will work
+
+ if (best_diag_price_in_heap <= diag_to_diag_price_ and best_diag_price_in_heap <= diag_unassigned_price_) {
+ best_diag_item_idx = best_diag_idx_in_heap;
+ best_diag_value = diag_edge_cost + best_diag_price_in_heap;
+ best_diag_price = best_diag_price_in_heap;
+ } else if (diag_to_diag_price_ < best_diag_price_in_heap and diag_to_diag_price_ < diag_unassigned_price_) {
+ best_diag_item_idx = *diag_assigned_to_diag_slice_.begin();
+ best_diag_value = diag_edge_cost + diag_to_diag_price_;
+ best_diag_price = diag_to_diag_price_;
+ } else {
+ best_diag_item_idx = *diag_unassigned_slice_.begin();
+ best_diag_value = diag_edge_cost + diag_unassigned_price_;
+ best_diag_price = diag_unassigned_price_;
+ }
+
+ }
+
+ if ( best_diag_value < best_normal_item_value) {
+ best_item_idx = best_diag_item_idx;
+ best_item_price = best_diag_price;
+ best_item_value = best_diag_value;
+ second_best_item_value = best_normal_item_value;
+ } else if (best_diag_value < second_best_normal_item_value) {
+ best_item_idx = best_normal_item_idx;
+ best_item_price = this->get_price(best_item_idx);
+ best_item_value = best_normal_item_value;
+ second_best_item_value = best_diag_value;
+ } else {
+ best_item_idx = best_normal_item_idx;
+ best_item_price = this->get_price(best_item_idx);
+ best_item_value = best_normal_item_value;
+ second_best_item_value = second_best_normal_item_value;
+ }
+
+ IdxValPair<Real> result;
+
+ result.first = best_item_idx;
+ result.second = ( second_best_item_value - best_item_value ) + best_item_price + this->epsilon;
+
+ //std::cout << "bidder_idx = " << bidder_idx << ", best_item_idx = " << best_item_idx << ", best_item_value = " << best_item_value << ", second_best_item_value = " << second_best_item_value << ", eps = " << this->epsilon << std::endl;
+ assert( second_best_item_value >= best_item_value );
+ //assert( best_item_price == this->get_price(best_item_idx) );
+ assert(result.second >= best_item_price);
+ sanity_check();
+
+ return result;
+}
+/*
+a_{ij} = d_{ij}
+price_{ij} = a_{ij} + price_j
+*/
+
+
+
+//template<class Real_, class PointContainer_>
+//std::vector<IdxValPairR> AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::increase_price_of_assigned_to_diag(WHAT)
+//{
+ //WHAT;
+//}
+//
+
+template<class Real_, class PointContainer_>
+Real_ AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::get_price(const size_t item_idx) const
+{
+ if (is_item_diagonal(item_idx)) {
+ if (diag_assigned_to_diag_slice_.count(item_idx) == 1) {
+ return diag_to_diag_price_;
+ } else if (diag_unassigned_slice_.count(item_idx) == 1) {
+ return diag_unassigned_price_;
+ }
+ }
+ return this-> prices[item_idx];
+}
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::set_price(const size_t item_idx,
+ const Real new_price,
+ const bool item_is_diagonal,
+ const bool bidder_is_diagonal,
+ const OwnerType old_owner_type)
+{
+
+ //std::cout << std::boolalpha << "enter set_price, item_idx = " << item_idx << ", new_price = " << new_price << ", old price = " << this->get_price(item_idx);
+ //std::cout << ", item_is_diagonal = " << item_is_diagonal << ", bidder_is_diagonal = " << bidder_is_diagonal << ", old_owner_type = " << old_owner_type << std::endl;
+
+ bool item_is_normal = not item_is_diagonal;
+ bool bidder_is_normal = not bidder_is_diagonal;
+
+ assert( new_price >= this->get_price(item_idx) );
+
+ // update vector prices
+ if (item_is_normal or bidder_is_normal) {
+ this->prices[item_idx] = new_price;
+ }
+
+ // update kdtree_
+ if (item_is_normal) {
+ assert(0 <= item_idx and item_idx < kdtree__items_.size());
+ assert(0 <= kdtree__items_[item_idx] and kdtree__items_[item_idx] < dnn_point_handles_.size());
+ kdtree_->change_weight( dnn_point_handles_[kdtree__items_[item_idx]], new_price);
+ }
+
+ // update all_items_heap_
+ if (bidder_is_diagonal and item_is_diagonal) {
+ // remove slice (item is buried in diag_assigned_to_diag_slice_)
+ assert(old_owner_type != OwnerType::k_diagonal);
+ auto iter = all_items_heap__iters_[item_idx];
+ assert(iter != all_items_heap_.end());
+ all_items_heap_.erase(iter);
+ all_items_heap__iters_[item_idx] = all_items_heap_.end();
+ } else {
+ auto iter = all_items_heap__iters_[item_idx];
+ if (iter != all_items_heap_.end()) {
+ // update existing element
+ ItemSliceR x = *iter;
+ x.set_loss( this->get_value_for_diagonal_bidder(item_idx) );
+ all_items_heap_.erase(iter);
+ auto ins_res = all_items_heap_.insert(x);
+ all_items_heap__iters_[item_idx] = ins_res.first;
+ assert(ins_res.second);
+ } else {
+ // insert new slice
+ // for diagonal items value = price
+ ItemSliceR x { item_idx, new_price };
+ auto ins_res = all_items_heap_.insert(x);
+ all_items_heap__iters_[item_idx] = ins_res.first;
+ assert(ins_res.second);
+ }
+ }
+
+ // update diag_items_heap_
+ if (item_is_diagonal and bidder_is_normal) {
+ // update existing element
+ auto iter = diag_items_heap__iters_[item_idx];
+ if (iter != diag_items_heap_.end()) {
+ ItemSliceR x = *iter;
+ x.set_loss( new_price );
+ diag_items_heap_.erase(iter);
+ auto ins_res = diag_items_heap_.insert(x);
+ diag_items_heap__iters_[item_idx] = ins_res.first;
+ assert(ins_res.second);
+ } else {
+ // insert new slice
+ // for diagonal items value = price
+ ItemSliceR x { item_idx, new_price };
+ auto ins_res = diag_items_heap_.insert(x);
+ diag_items_heap__iters_[item_idx] = ins_res.first;
+ assert(ins_res.second);
+ }
+ } else if (bidder_is_diagonal and item_is_diagonal ) {
+ // remove slice (item is buried in diag_assigned_to_diag_slice_)
+ assert(old_owner_type != OwnerType::k_diagonal);
+ auto iter = diag_items_heap__iters_[item_idx];
+ assert(iter != diag_items_heap_.end());
+ diag_items_heap_.erase(iter);
+ diag_items_heap__iters_[item_idx] = diag_items_heap_.end();
+ }
+
+ // update diag_unassigned_price_
+ if (item_is_diagonal and old_owner_type == OwnerType::k_none and diag_unassigned_slice_.empty()) {
+ diag_unassigned_price_ = std::numeric_limits<Real>::max();
+ }
+
+}
+
+
+template<class Real_, class PointContainer_>
+bool AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::is_item_diagonal(const size_t item_idx) const
+{
+ return item_idx < this->num_diag_items_;
+}
+
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::flush_assignment()
+{
+ //std::cout << "enter oracle->flush_assignment" << std::endl;
+ sanity_check();
+
+ for(const auto item_idx : diag_assigned_to_diag_slice_) {
+ diag_unassigned_slice_.insert(item_idx);
+ }
+ diag_assigned_to_diag_slice_.clear();
+
+ // common price of diag-diag items becomes price of diag-unassigned-slice
+ // diag_to_diag_slice is now empty, set its price to max
+ // so that get_optimal_bid works correctly
+ diag_unassigned_price_ = diag_to_diag_price_;
+ diag_to_diag_price_ = std::numeric_limits<Real>::max();
+
+ normal_items_assigned_to_diag_.clear();
+
+ sanity_check();
+}
+
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::adjust_prices()
+{
+ return;
+
+ throw std::runtime_error("not implemented");
+ auto pr_begin = this->prices.begin();
+ auto pr_end = this->prices.end();
+
+ Real min_price = *(std::min_element(pr_begin, pr_end));
+
+ for(auto& p : this->prices) {
+ p -= min_price;
+ }
+
+ kdtree_->adjust_weights(min_price);
+ diag_items_heap_.adjust_prices(min_price);
+ all_items_heap_.adjust_prices(min_price);
+}
+
+
+template<class Real_, class PointContainer_>
+AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::~AuctionOracleKDTreeSingleDiag()
+{
+ delete kdtree_;
+}
+
+template<class Real_, class PointContainer_>
+void AuctionOracleKDTreeSingleDiag<Real_, PointContainer_>::sanity_check()
+{
+#ifdef DEBUG_AUCTION
+
+ //std::cout << "ORACLE CURRENT STATE IN SANITY CHECK" << *this << std::endl;
+
+ assert( diag_items_heap_.size() + diag_assigned_to_diag_slice_.size() + diag_unassigned_slice_.size() == num_diag_items_ );
+ assert( diag_items_heap__iters_.size() == num_diag_items_ );
+ for(size_t i = 0; i < num_diag_items_; ++i) {
+ if (diag_items_heap__iters_.at(i) != diag_items_heap_.end()) {
+ assert(diag_items_heap__iters_[i]->item_idx == i);
+ }
+ }
+
+ assert( all_items_heap_.size() + diag_assigned_to_diag_slice_.size() + diag_unassigned_slice_.size() == this->num_items_ );
+ assert( all_items_heap__iters_.size() == this->num_items_ );
+ for(size_t i = 0; i < this->num_items_; ++i) {
+ if (all_items_heap__iters_.at(i) != all_items_heap_.end()) {
+ assert(all_items_heap__iters_[i]->item_idx == i);
+ } else {
+ assert( i < num_diag_items_ );
+ }
+ }
+
+ for(size_t i = 0; i < num_diag_items_; ++i) {
+ int is_in_assigned_slice = diag_assigned_to_diag_slice_.count(i);
+ int is_in_unassigned_slice = diag_unassigned_slice_.count(i);
+ int is_in_heap = diag_items_heap__iters_[i] != diag_items_heap_.end();
+ assert( is_in_assigned_slice + is_in_unassigned_slice + is_in_heap == 1);
+ }
+
+ //assert((diag_assigned_to_diag_slice_.empty() and diag_to_diag_price_ == std::numeric_limits<Real>::max()) or (not diag_assigned_to_diag_slice_.empty() and diag_to_diag_price_ != std::numeric_limits<Real>::max()));
+ //assert((diag_unassigned_slice_.empty() and diag_unassigned_price_ == std::numeric_limits<Real>::max()) or (not diag_unassigned_slice_.empty() and diag_unassigned_price_ != std::numeric_limits<Real>::max()));
+
+ assert(diag_assigned_to_diag_slice_.empty() or diag_to_diag_price_ != std::numeric_limits<Real>::max());
+ assert(diag_unassigned_slice_.empty() or diag_unassigned_price_ != std::numeric_limits<Real>::max());
+#endif
+}
+
+
+} // ws
+} // hera
+#endif
diff --git a/wasserstein/include/auction_oracle_lazy_heap.h b/wasserstein/include/auction_oracle_lazy_heap.h
new file mode 100644
index 0000000..8b37421
--- /dev/null
+++ b/wasserstein/include/auction_oracle_lazy_heap.h
@@ -0,0 +1,191 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_ORACLE_LAZY_HEAP_H
+#define AUCTION_ORACLE_LAZY_HEAP_H
+
+
+#define USE_BOOST_HEAP
+
+#include <map>
+#include <memory>
+#include <set>
+#include <list>
+
+#ifdef USE_BOOST_HEAP
+#include <boost/heap/d_ary_heap.hpp>
+#endif
+
+#include "basic_defs_ws.h"
+
+namespace ws {
+
+template <typename T>
+struct CompPairsBySecondStruct {
+ bool operator()(const IdxValPair<T>& a, const IdxValPair<T>& b) const
+ {
+ return a.second < b.second;
+ }
+};
+
+
+template <typename T>
+struct CompPairsBySecondGreaterStruct {
+ bool operator()(const IdxValPair<T>& a, const IdxValPair<T>& b) const
+ {
+ return a.second > b.second;
+ }
+};
+
+template <typename T>
+struct CompPairsBySecondLexStruct {
+ bool operator()(const IdxValPair<T>& a, const IdxValPair<T>& b) const
+ {
+ return a.second < b.second or (a.second == b.second and a.first > b.first);
+ }
+};
+
+template <typename T>
+struct CompPairsBySecondLexGreaterStruct {
+ bool operator()(const IdxValPair<T>& a, const IdxValPair<T>& b) const
+ {
+ return a.second > b.second or (a.second == b.second and a.first > b.first);
+ }
+};
+
+using ItemsTimePair = std::pair<IdxType, int>;
+using UpdateList = std::list<ItemsTimePair>;
+using UpdateListIter = UpdateList::iterator;
+
+
+#ifdef USE_BOOST_HEAP
+template <class Real>
+using LossesHeap = boost::heap::d_ary_heap<IdxValPair<Real>, boost::heap::arity<2>, boost::heap::mutable_<true>, boost::heap::compare<CompPairsBySecondGreaterStruct<Real>>>;
+#else
+template<typename T, class ComparisonStruct>
+class IdxValHeap {
+public:
+ using InternalKeeper = std::set<IdxValPair<T>, ComparisonStruct>;
+ using handle_type = typename InternalKeeper::iterator;
+ // methods
+ handle_type push(const IdxValPair<T>& val)
+ {
+ auto res_pair = _heap.insert(val);
+ assert(res_pair.second);
+ assert(res_pair.first != _heap.end());
+ return res_pair.first;
+ }
+
+ void decrease(handle_type& handle, const IdxValPair<T>& new_val)
+ {
+ _heap.erase(handle);
+ handle = push(new_val);
+ }
+
+ void increase(handle_type& handle, const IdxValPair<T>& new_val)
+ {
+ _heap.erase(handle);
+ handle = push(new_val);
+
+ size_t size() const
+ {
+ return _heap.size();
+ }
+
+ handle_type ordered_begin()
+ {
+ return _heap.begin();
+ }
+
+ handle_type ordered_end()
+ {
+ return _heap.end();
+ }
+
+
+private:
+ std::set<IdxValPair<T>, ComparisonStruct> _heap;
+};
+
+// if we store losses, the minimal value should come first
+template <class Real>
+using LossesHeap = IdxValHeap<Real, CompPairsBySecondLexStruct>;
+#endif
+
+
+template <class Real = double>
+struct AuctionOracleLazyHeapRestricted : AuctionOracleBase<Real> {
+
+ using LossesHeapR = typename ws::LossesHeap<Real>;
+ using LossesHeapRHandle = typename ws::LossesHeap<Real>::handle_type;
+ using DiagramPointR = typename ws::DiagramPoint<Real>;
+
+
+ AuctionOracleLazyHeapRestricted(const std::vector<DiagramPointR>& bidders, const std::vector<DiagramPointR>& items, const Real wasserstein_power, const Real _internal_p = get_infinity<Real>());
+ ~AuctionOracleLazyHeapRestricted();
+ // data members
+ // temporarily make everything public
+ std::vector<std::vector<Real>> weight_matrix;
+ //Real weight_adj_const;
+ Real max_val;
+ // vector of heaps to find the best items
+ std::vector<LossesHeapR*> losses_heap;
+ std::vector<std::vector<size_t>> items_indices_for_heap_handles;
+ std::vector<std::vector<LossesHeapRHandle>> losses_heap_handles;
+ // methods
+ void fill_in_losses_heap();
+ void set_price(const IdxType items_idx, const Real new_price);
+ IdxValPair<Real> get_optimal_bid(const IdxType bidder_idx);
+ Real get_matching_weight(const std::vector<IdxType>& bidders_to_items) const;
+ void adjust_prices();
+ // to update the queue in lazy fashion
+ std::vector<UpdateListIter> items_iterators;
+ UpdateList update_list;
+ std::vector<int> bidders_update_moments;
+ int update_counter;
+ void update_queue_for_bidder(const IdxType bidder_idx);
+ LossesHeapR diag_items_heap;
+ std::vector<LossesHeapRHandle> diag_heap_handles;
+ std::vector<size_t> heap_handles_indices;
+ // debug
+
+ DebugOptimalBid<Real> get_optimal_bid_debug(const IdxType bidder_idx);
+
+ // for diagonal points
+ bool best_diagonal_items_computed;
+ size_t best_diagonal_item_idx;
+ Real best_diagonal_item_value;
+ size_t second_best_diagonal_item_idx;
+ Real second_best_diagonal_item_value;
+};
+
+} // end of namespace ws
+
+#include "auction_oracle_lazy_heap.h"
+
+#endif
diff --git a/wasserstein/include/auction_oracle_lazy_heap.hpp b/wasserstein/include/auction_oracle_lazy_heap.hpp
new file mode 100644
index 0000000..d179b3d
--- /dev/null
+++ b/wasserstein/include/auction_oracle_lazy_heap.hpp
@@ -0,0 +1,465 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#include <assert.h>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+#include "def_debug_ws.h"
+#include "auction_oracle.h"
+
+
+#ifdef FOR_R_TDA
+#undef DEBUG_AUCTION
+#endif
+
+namespace ws {
+
+// *****************************
+// AuctionOracleLazyHeapRestricted
+// *****************************
+
+
+template<class Real>
+AuctionOracleLazyHeapRestricted<Real>::AuctionOracleLazyHeapRestricted(const std::vector<DiagramPoint<Real>>& _bidders,
+ const std::vector<DiagramPoint<Real>>& _items,
+ Real _wasserstein_power,
+ Real _internal_p) :
+ AuctionOracleAbstract<Real>(_bidders, _items, _wasserstein_power, _internal_p),
+ max_val(0.0),
+ bidders_update_moments(_bidders.size(), 0),
+ update_counter(0),
+ heap_handles_indices(_items.size(), k_invalid_index),
+ best_diagonal_items_computed(false)
+{
+ weight_matrix.reserve(_bidders.size());
+ //const Real max_dist_upper_bound = 3 * getFurthestDistance3Approx(b, g);
+ //weight_adj_const = pow(max_dist_upper_bound, wasserstein_power);
+ // init weight matrix
+ for(const auto& point_A : _bidders) {
+ std::vector<Real> weight_vec;
+ weight_vec.clear();
+ weight_vec.reserve(_bidders.size());
+ for(const auto& point_B : _items) {
+ Real val = pow(dist_lp(point_A, point_B, _internal_p), _wasserstein_power);
+ weight_vec.push_back( val );
+ if ( val > max_val )
+ max_val = val;
+ }
+ weight_matrix.push_back(weight_vec);
+ }
+ fill_in_losses_heap();
+ for(size_t item_idx = 0; item_idx < _items.size(); ++item_idx) {
+ update_list.push_back(std::make_pair(static_cast<IdxType>(item_idx), 0));
+ }
+ for(auto update_list_iter = update_list.begin(); update_list_iter != update_list.end(); ++update_list_iter) {
+ items_iterators.push_back(update_list_iter);
+ }
+
+ size_t handle_idx {0};
+ for(size_t item_idx = 0; item_idx < _items.size(); ++item_idx) {
+ if (_items[item_idx].is_diagonal() ) {
+ heap_handles_indices[item_idx] = handle_idx++;
+ diag_heap_handles.push_back(diag_items_heap.push(std::make_pair(item_idx, 0)));
+ }
+ }
+}
+
+
+template<class Real>
+void AuctionOracleLazyHeapRestricted<Real>::update_queue_for_bidder(IdxType bidder_idx)
+{
+ assert(0 <= bidder_idx and bidder_idx < static_cast<int>(this->bidders.size()));
+ assert(bidder_idx < static_cast<int>(bidders_update_moments.size()));
+ assert(losses_heap[bidder_idx] != nullptr );
+
+ int bidder_last_update_time = bidders_update_moments[bidder_idx];
+ auto iter = update_list.begin();
+ while (iter != update_list.end() and iter->second >= bidder_last_update_time) {
+ IdxType item_idx = iter->first;
+ size_t handle_idx = items_indices_for_heap_handles[bidder_idx][item_idx];
+ if (handle_idx < this->items.size() ) {
+ IdxValPair<Real> new_val { item_idx, weight_matrix[bidder_idx][item_idx] + this->prices[item_idx]};
+ // to-do: change indexing of losses_heap_handles
+ losses_heap[bidder_idx]->decrease(losses_heap_handles[bidder_idx][handle_idx], new_val);
+ }
+ iter++;
+ }
+ bidders_update_moments[bidder_idx] = update_counter;
+}
+
+
+template<class Real>
+void AuctionOracleLazyHeapRestricted<Real>::fill_in_losses_heap()
+{
+ using LossesHeapR = typename ws::LossesHeap<Real>;
+ using LossesHeapRHandleVec = typename std::vector<typename ws::LossesHeap<Real>::handle_type>;
+
+ for(size_t bidder_idx = 0; bidder_idx < this->bidders.size(); ++bidder_idx) {
+ DiagramPoint<Real> bidder { this->bidders[bidder_idx] };
+ // no heap for diagonal bidders
+ if ( bidder.is_diagonal() ) {
+ losses_heap.push_back( nullptr );
+ losses_heap_handles.push_back(LossesHeapRHandleVec());
+ items_indices_for_heap_handles.push_back( std::vector<size_t>() );
+ continue;
+ } else {
+ losses_heap.push_back( new LossesHeapR() );
+
+ assert( losses_heap.at(bidder_idx) != nullptr );
+
+ items_indices_for_heap_handles.push_back( std::vector<size_t>(this->items.size(), k_invalid_index) );
+ LossesHeapRHandleVec handles_vec;
+ losses_heap_handles.push_back(handles_vec);
+ size_t handle_idx { 0 };
+ for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ assert( items_indices_for_heap_handles.at(bidder_idx).at(item_idx) > 0 );
+ DiagramPoint<Real> item { this->items[item_idx] };
+ if ( item.is_normal() ) {
+ // item can be assigned to bidder, store in heap
+ IdxValPair<Real> vp { item_idx, weight_matrix[bidder_idx][item_idx] + this->prices[item_idx] };
+ losses_heap_handles[bidder_idx].push_back( losses_heap[bidder_idx]->push(vp) );
+ // keep corresponding index in items_indices_for_heap_handles
+ items_indices_for_heap_handles[bidder_idx][item_idx] = handle_idx++;
+ }
+ }
+ }
+ }
+}
+
+
+template<class Real>
+AuctionOracleLazyHeapRestricted<Real>::~AuctionOracleLazyHeapRestricted()
+{
+ for(auto h : losses_heap) {
+ delete h;
+ }
+}
+
+
+template<class Real>
+void AuctionOracleLazyHeapRestricted<Real>::set_price(IdxType item_idx, Real new_price)
+{
+ assert( this->prices.at(item_idx) < new_price );
+#ifdef DEBUG_AUCTION
+ std::cout << "price incremented by " << this->prices.at(item_idx) - new_price << std::endl;
+#endif
+ this->prices[item_idx] = new_price;
+ if (this->items[item_idx].is_normal() ) {
+ // lazy: record the moment we updated the price of the items,
+ // do not update queues.
+ // 1. move the items with updated price to the front of the update_list,
+ update_list.splice(update_list.begin(), update_list, items_iterators[item_idx]);
+ // 2. record the moment we updated the price and increase the counter
+ update_list.front().second = update_counter++;
+ } else {
+ // diagonal items are stored in one heap
+ diag_items_heap.decrease(diag_heap_handles[heap_handles_indices[item_idx]], std::make_pair(item_idx, new_price));
+ best_diagonal_items_computed = false;
+ }
+}
+
+// subtract min. price from all prices
+template<class Real>
+void AuctionOracleLazyHeapRestricted<Real>::adjust_prices()
+{
+}
+
+
+template<class Real>
+DebugOptimalBid<Real> AuctionOracleLazyHeapRestricted<Real>::get_optimal_bid_debug(IdxType bidder_idx)
+{
+ DebugOptimalBid<Real> result;
+ assert(bidder_idx >=0 and bidder_idx < static_cast<IdxType>(this->bidders.size()) );
+
+ auto bidder = this->bidders[bidder_idx];
+ std::vector<IdxValPair<Real>> cand_items;
+ // corresponding point is always considered as a candidate
+
+ size_t proj_item_idx = bidder_idx;
+ assert( 0 <= proj_item_idx and proj_item_idx < this->items.size() );
+ auto proj_item = this->items[proj_item_idx];
+ assert(proj_item.type != bidder.type);
+ //assert(proj_item.proj_id == bidder.id);
+ //assert(proj_item.id == bidder.proj_id);
+ // todo: store precomputed distance?
+ Real proj_item_value = this->get_value_for_bidder(bidder_idx, proj_item_idx);
+ cand_items.push_back( std::make_pair(proj_item_idx, proj_item_value) );
+
+ if (bidder.is_normal()) {
+ assert(losses_heap.at(bidder_idx) != nullptr);
+ assert(losses_heap[bidder_idx]->size() >= 2);
+ update_queue_for_bidder(bidder_idx);
+ auto pHeap = losses_heap[bidder_idx];
+ assert( pHeap != nullptr );
+ auto top_iter = pHeap->ordered_begin();
+ cand_items.push_back( *top_iter );
+ ++top_iter; // now points to the second-best items
+ cand_items.push_back( *top_iter );
+ std::sort(cand_items.begin(), cand_items.end(), CompPairsBySecondStruct<Real>());
+ assert(cand_items[1].second >= cand_items[0].second);
+ } else {
+ // for diagonal bidder the only normal point has already been added
+ // the other 2 candidates are diagonal items only, get from the heap
+ // with prices
+ assert(diag_items_heap.size() > 1);
+ auto top_diag_iter = diag_items_heap.ordered_begin();
+ auto topDiag1 = *top_diag_iter++;
+ auto topDiag2 = *top_diag_iter;
+ cand_items.push_back(topDiag1);
+ cand_items.push_back(topDiag2);
+ std::sort(cand_items.begin(), cand_items.end(), CompPairsBySecondStruct<Real>());
+ assert(cand_items.size() == 3);
+ assert(cand_items[2].second >= cand_items[1].second);
+ assert(cand_items[1].second >= cand_items[0].second);
+ }
+
+ result.best_item_idx = cand_items[0].first;
+ result.second_best_item_idx = cand_items[1].first;
+ result.best_item_value = cand_items[0].second;
+ result.second_best_item_value = cand_items[1].second;
+
+ // checking code
+
+ //DebugOptimalBid<Real> debug_my_result(result);
+ //DebugOptimalBid<Real> debug_naive_result;
+ //debug_naive_result.best_item_value = 1e20;
+ //debug_naive_result.second_best_item_value = 1e20;
+ //Real curr_item_value;
+ //for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ //if ( this->bidders[bidder_idx].type != this->items[item_idx].type and
+ //this->bidders[bidder_idx].proj_id != this->items[item_idx].id)
+ //continue;
+
+ //curr_item_value = pow(dist_lp(this->bidders[bidder_idx], this->items[item_idx]), wasserstein_power) + this->prices[item_idx];
+ //if (curr_item_value < debug_naive_result.best_item_value) {
+ //debug_naive_result.best_item_value = curr_item_value;
+ //debug_naive_result.best_item_idx = item_idx;
+ //}
+ //}
+
+ //for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ //if (item_idx == debug_naive_result.best_item_idx) {
+ //continue;
+ //}
+ //if ( this->bidders[bidder_idx].type != this->items[item_idx].type and
+ //this->bidders[bidder_idx].proj_id != this->items[item_idx].id)
+ //continue;
+
+ //curr_item_value = pow(dist_lp(this->bidders[bidder_idx], this->items[item_idx]), wasserstein_power) + this->prices[item_idx];
+ //if (curr_item_value < debug_naive_result.second_best_item_value) {
+ //debug_naive_result.second_best_item_value = curr_item_value;
+ //debug_naive_result.second_best_item_idx = item_idx;
+ //}
+ //}
+
+ //if ( fabs( debug_my_result.best_item_value - debug_naive_result.best_item_value ) > 1e-6 or
+ //fabs( debug_naive_result.second_best_item_value - debug_my_result.second_best_item_value) > 1e-6 ) {
+ //std::cerr << "bidder_idx = " << bidder_idx << "; ";
+ //std::cerr << this->bidders[bidder_idx] << std::endl;
+ //for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ //std::cout << item_idx << ": " << this->items[item_idx] << "; price = " << this->prices[item_idx] << std::endl;
+ //}
+ //std::cerr << "debug_my_result: " << debug_my_result << std::endl;
+ //std::cerr << "debug_naive_result: " << debug_naive_result << std::endl;
+ //auto pHeap = losses_heap[bidder_idx];
+ //assert( pHeap != nullptr );
+ //for(auto top_iter = pHeap->ordered_begin(); top_iter != pHeap->ordered_end(); ++top_iter) {
+ //std::cerr << "in heap: " << top_iter->first << ": " << top_iter->second << "; real value = " << dist_lp(bidder, this->items[top_iter->first]) + this->prices[top_iter->first] << std::endl;
+ //}
+ //for(auto ci : cand_items) {
+ //std::cout << "ci.idx = " << ci.first << ", value = " << ci.second << std::endl;
+ //}
+
+ ////std::cerr << "two_best_items: " << two_best_items[0].d << " " << two_best_items[1].d << std::endl;
+ //assert(false);
+ //}
+
+
+ //std::cout << "get_optimal_bid: bidder_idx = " << bidder_idx << "; best_item_idx = " << best_item_idx << "; best_item_value = " << best_item_value << "; best_items_price = " << this->prices[best_item_idx] << "; second_best_item_idx = " << top_iter->first << "; second_best_value = " << second_best_item_value << "; second_best_price = " << this->prices[top_iter->first] << "; bid = " << this->prices[best_item_idx] + ( best_item_value - second_best_item_value ) + epsilon << "; epsilon = " << epsilon << std::endl;
+ //std::cout << "get_optimal_bid: bidder_idx = " << bidder_idx << "; best_item_idx = " << best_item_idx << "; best_items_dist= " << (weight_adj_const - best_item_value) << "; best_items_price = " << this->prices[best_item_idx] << "; second_best_item_idx = " << top_iter->first << "; second_best_dist= " << (weight_adj_const - second_best_item_value) << "; second_best_price = " << this->prices[top_iter->first] << "; bid = " << this->prices[best_item_idx] + ( best_item_value - second_best_item_value ) + epsilon << "; epsilon = " << epsilon << std::endl;
+
+ return result;
+}
+
+
+template<class Real>
+IdxValPair<Real> AuctionOracleLazyHeapRestricted<Real>::get_optimal_bid(const IdxType bidder_idx)
+{
+ IdxType best_item_idx;
+ //IdxType second_best_item_idx;
+ Real best_item_value;
+ Real second_best_item_value;
+
+ auto& bidder = this->bidders[bidder_idx];
+ IdxType proj_item_idx = bidder_idx;
+ assert( 0 <= proj_item_idx and proj_item_idx < this->items.size() );
+ auto proj_item = this->items[proj_item_idx];
+ assert(proj_item.type != bidder.type);
+ //assert(proj_item.proj_id == bidder.id);
+ //assert(proj_item.id == bidder.proj_id);
+ // todo: store precomputed distance?
+ Real proj_item_value = this->get_value_for_bidder(bidder_idx, proj_item_idx);
+
+ if (bidder.is_diagonal()) {
+ // for diagonal bidder the only normal point has already been added
+ // the other 2 candidates are diagonal items only, get from the heap
+ // with prices
+ assert(diag_items_heap.size() > 1);
+ if (!best_diagonal_items_computed) {
+ auto top_diag_iter = diag_items_heap.ordered_begin();
+ best_diagonal_item_idx = top_diag_iter->first;
+ best_diagonal_item_value = top_diag_iter->second;
+ top_diag_iter++;
+ second_best_diagonal_item_idx = top_diag_iter->first;
+ second_best_diagonal_item_value = top_diag_iter->second;
+ best_diagonal_items_computed = true;
+ }
+
+ if ( proj_item_value < best_diagonal_item_value) {
+ best_item_idx = proj_item_idx;
+ best_item_value = proj_item_value;
+ second_best_item_value = best_diagonal_item_value;
+ //second_best_item_idx = best_diagonal_item_idx;
+ } else if (proj_item_value < second_best_diagonal_item_value) {
+ best_item_idx = best_diagonal_item_idx;
+ best_item_value = best_diagonal_item_value;
+ second_best_item_value = proj_item_value;
+ //second_best_item_idx = proj_item_idx;
+ } else {
+ best_item_idx = best_diagonal_item_idx;
+ best_item_value = best_diagonal_item_value;
+ second_best_item_value = second_best_diagonal_item_value;
+ //second_best_item_idx = second_best_diagonal_item_idx;
+ }
+ } else {
+ // for normal bidder get 2 best items among non-diagonal (=normal) points
+ // from the corresponding heap
+ assert(diag_items_heap.size() > 1);
+ update_queue_for_bidder(bidder_idx);
+ auto top_norm_iter = losses_heap[bidder_idx]->ordered_begin();
+ IdxType best_normal_item_idx { top_norm_iter->first };
+ Real best_normal_item_value { top_norm_iter->second };
+ top_norm_iter++;
+ Real second_best_normal_item_value { top_norm_iter->second };
+ //IdxType second_best_normal_item_idx { top_norm_iter->first };
+
+ if ( proj_item_value < best_normal_item_value) {
+ best_item_idx = proj_item_idx;
+ best_item_value = proj_item_value;
+ second_best_item_value = best_normal_item_value;
+ //second_best_item_idx = best_normal_item_idx;
+ } else if (proj_item_value < second_best_normal_item_value) {
+ best_item_idx = best_normal_item_idx;
+ best_item_value = best_normal_item_value;
+ second_best_item_value = proj_item_value;
+ //second_best_item_idx = proj_item_idx;
+ } else {
+ best_item_idx = best_normal_item_idx;
+ best_item_value = best_normal_item_value;
+ second_best_item_value = second_best_normal_item_value;
+ //second_best_item_idx = second_best_normal_item_idx;
+ }
+ }
+
+ IdxValPair<Real> result;
+
+ assert( second_best_item_value >= best_item_value );
+
+ result.first = best_item_idx;
+ result.second = ( second_best_item_value - best_item_value ) + this->prices[best_item_idx] + this->epsilon;
+
+
+ // checking code
+
+ //DebugOptimalBid<Real> debug_my_result;
+ //debug_my_result.best_item_idx = best_item_idx;
+ //debug_my_result.best_item_value = best_item_value;
+ //debug_my_result.second_best_item_idx = second_best_item_idx;
+ //debug_my_result.second_best_item_value = second_best_item_value;
+ //DebugOptimalBid<Real> debug_naive_result;
+ //debug_naive_result.best_item_value = 1e20;
+ //debug_naive_result.second_best_item_value = 1e20;
+ //Real curr_item_value;
+ //for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ //if ( this->bidders[bidder_idx].type != this->items[item_idx].type and
+ //this->bidders[bidder_idx].proj_id != this->items[item_idx].id)
+ //continue;
+
+ //curr_item_value = this->get_value_for_bidder(bidder_idx, item_idx);
+ //if (curr_item_value < debug_naive_result.best_item_value) {
+ //debug_naive_result.best_item_value = curr_item_value;
+ //debug_naive_result.best_item_idx = item_idx;
+ //}
+ //}
+
+ //for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ //if (item_idx == debug_naive_result.best_item_idx) {
+ //continue;
+ //}
+ //if ( this->bidders[bidder_idx].type != this->items[item_idx].type and
+ //this->bidders[bidder_idx].proj_id != this->items[item_idx].id)
+ //continue;
+
+ //curr_item_value = this->get_value_for_bidder(bidder_idx, item_idx);
+ //if (curr_item_value < debug_naive_result.second_best_item_value) {
+ //debug_naive_result.second_best_item_value = curr_item_value;
+ //debug_naive_result.second_best_item_idx = item_idx;
+ //}
+ //}
+ ////std::cout << "got naive result" << std::endl;
+
+ //if ( fabs( debug_my_result.best_item_value - debug_naive_result.best_item_value ) > 1e-6 or
+ //fabs( debug_naive_result.second_best_item_value - debug_my_result.second_best_item_value) > 1e-6 ) {
+ //std::cerr << "bidder_idx = " << bidder_idx << "; ";
+ //std::cerr << this->bidders[bidder_idx] << std::endl;
+ //for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ //std::cout << item_idx << ": " << this->items[item_idx] << "; price = " << this->prices[item_idx] << std::endl;
+ //}
+ //std::cerr << "debug_my_result: " << debug_my_result << std::endl;
+ //std::cerr << "debug_naive_result: " << debug_naive_result << std::endl;
+ //auto pHeap = losses_heap[bidder_idx];
+ //if ( pHeap != nullptr ) {
+ //for(auto top_iter = pHeap->ordered_begin(); top_iter != pHeap->ordered_end(); ++top_iter) {
+ //std::cerr << "in heap: " << top_iter->first << ": " << top_iter->second << "; real value = " << dist_lp(bidder, this->items[top_iter->first]) + this->prices[top_iter->first] << std::endl;
+ //}
+ //}
+ ////for(auto ci : cand_items) {
+ ////std::cout << "ci.idx = " << ci.first << ", value = " << ci.second << std::endl;
+ ////}
+
+ ////std::cerr << "two_best_items: " << two_best_items[0].d << " " << two_best_items[1].d << std::endl;
+ //assert(false);
+ // }
+ //std::cout << "get_optimal_bid: bidder_idx = " << bidder_idx << "; best_item_idx = " << best_item_idx << "; best_item_value = " << best_item_value << "; best_items_price = " << this->prices[best_item_idx] << "; second_best_item_idx = " << top_iter->first << "; second_best_value = " << second_best_item_value << "; second_best_price = " << this->prices[top_iter->first] << "; bid = " << this->prices[best_item_idx] + ( best_item_value - second_best_item_value ) + epsilon << "; epsilon = " << epsilon << std::endl;
+ //std::cout << "get_optimal_bid: bidder_idx = " << bidder_idx << "; best_item_idx = " << best_item_idx << "; best_items_dist= " << (weight_adj_const - best_item_value) << "; best_items_price = " << this->prices[best_item_idx] << "; second_best_item_idx = " << top_iter->first << "; second_best_dist= " << (weight_adj_const - second_best_item_value) << "; second_best_price = " << this->prices[top_iter->first] << "; bid = " << this->prices[best_item_idx] + ( best_item_value - second_best_item_value ) + epsilon << "; epsilon = " << epsilon << std::endl;
+
+ return result;
+}
+
+} // end of namespace ws
diff --git a/wasserstein/include/auction_oracle_stupid_sparse_restricted.h b/wasserstein/include/auction_oracle_stupid_sparse_restricted.h
new file mode 100644
index 0000000..df63daf
--- /dev/null
+++ b/wasserstein/include/auction_oracle_stupid_sparse_restricted.h
@@ -0,0 +1,112 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_ORACLE_STUPID_SPARSE_RESTRICTED_H
+#define AUCTION_ORACLE_STUPID_SPARSE_RESTRICTED_H
+
+#include <map>
+#include <memory>
+#include <set>
+
+#include "basic_defs_ws.h"
+#include "diagonal_heap.h"
+#include "auction_oracle_base.h"
+#include "dnn/geometry/euclidean-fixed.h"
+#include "dnn/local/kd-tree.h"
+
+
+namespace hera {
+namespace ws {
+
+template <int k_max_nn, class Real_ = double, class PointContainer_ = std::vector<DiagramPoint<Real_>>>
+struct AuctionOracleStupidSparseRestricted : AuctionOracleBase<Real_, PointContainer_> {
+
+ using PointContainer = PointContainer_;
+ using Real = Real_;
+
+ using LossesHeapR = typename ws::LossesHeapOld<Real>;
+ using LossesHeapRHandle = typename ws::LossesHeapOld<Real>::handle_type;
+ using DiagramPointR = typename ws::DiagramPoint<Real>;
+ using DebugOptimalBidR = typename ws::DebugOptimalBid<Real>;
+
+ using DnnPoint = dnn::Point<2, Real>;
+ using DnnTraits = dnn::PointTraits<DnnPoint>;
+
+
+ AuctionOracleStupidSparseRestricted(const PointContainer& bidders, const PointContainer& items, const AuctionParams<Real>& params);
+ // data members
+ // temporarily make everything public
+ std::vector<std::vector<size_t>> admissible_items_;
+ Real max_val_;
+ LossesHeapR diag_items_heap_;
+ std::vector<LossesHeapRHandle> diag_heap_handles_;
+ std::vector<size_t> heap_handles_indices_;
+
+// std::vector<size_t> kdtree_items_;
+
+ std::vector<size_t> top_diag_indices_;
+ std::vector<size_t> top_diag_lookup_;
+ size_t top_diag_counter_ { 0 };
+ bool best_diagonal_items_computed_ { false };
+ Real best_diagonal_item_value_;
+ Real second_best_diagonal_item_idx_ { k_invalid_index };
+ Real second_best_diagonal_item_value_ { std::numeric_limits<Real>::max() };
+
+
+ // methods
+ void set_price(const IdxType items_idx, const Real new_price, const bool update_diag = true);
+ IdxValPair<Real> get_optimal_bid(const IdxType bidder_idx);
+ void adjust_prices();
+ void adjust_prices(const Real delta);
+
+ // debug routines
+ DebugOptimalBidR get_optimal_bid_debug(IdxType bidder_idx) const;
+ void sanity_check();
+
+
+ // heap top vector
+ size_t get_heap_top_size() const;
+ void recompute_top_diag_items(bool hard = false);
+ void recompute_second_best_diag();
+ void reset_top_diag_counter();
+ void increment_top_diag_counter();
+ void add_top_diag_index(const size_t item_idx);
+ void remove_top_diag_index(const size_t item_idx);
+ bool is_in_top_diag_indices(const size_t item_idx) const;
+
+ std::pair<Real, Real> get_minmax_price() const;
+
+};
+
+} // ws
+} // hera
+
+
+#include "auction_oracle_stupid_sparse_restricted.hpp"
+
+#endif
diff --git a/wasserstein/include/auction_oracle_stupid_sparse_restricted.hpp b/wasserstein/include/auction_oracle_stupid_sparse_restricted.hpp
new file mode 100644
index 0000000..9df2874
--- /dev/null
+++ b/wasserstein/include/auction_oracle_stupid_sparse_restricted.hpp
@@ -0,0 +1,521 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+#ifndef AUCTION_ORACLE_STUPID_SPARSE_HPP
+#define AUCTION_ORACLE_STUPID_SPARSE_HPP
+
+#include <assert.h>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+#include "def_debug_ws.h"
+#include "basic_defs_ws.h"
+#include "auction_oracle_stupid_sparse_restricted.h"
+
+#ifdef FOR_R_TDA
+#undef DEBUG_AUCTION
+#endif
+
+namespace hera {
+namespace ws {
+
+
+// *****************************
+// AuctionOracleStupidSparseRestricted
+// *****************************
+
+
+template <int k_max_nn, class Real_, class PointContainer_>
+std::ostream& operator<<(std::ostream& output, const AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>& oracle)
+{
+ output << "Oracle: " << &oracle << std::endl;
+ output << "max_val_ = " << oracle.max_val_ << ", ";
+ output << "best_diagonal_items_computed_ = " << oracle.best_diagonal_items_computed_ << ", ";
+ output << "best_diagonal_item_value_ = " << oracle.best_diagonal_item_value_ << ", ";
+ output << "second_best_diagonal_item_idx_ = " << oracle.second_best_diagonal_item_idx_ << ", ";
+ output << "second_best_diagonal_item_value_ = " << oracle.second_best_diagonal_item_value_ << ", ";
+ output << "prices = " << format_container_to_log(oracle.prices) << "\n";
+ output << "diag_items_heap_ = " << losses_heap_to_string(oracle.diag_items_heap_) << "\n";
+ output << "top_diag_indices_ = " << format_container_to_log(oracle.top_diag_indices_) << "\n";
+ output << "top_diag_counter_ = " << oracle.top_diag_counter_ << "\n";
+ output << "top_diag_lookup_ = " << format_container_to_log(oracle.top_diag_lookup_) << "\n";
+ output << "end of oracle " << &oracle << std::endl;
+ return output;
+}
+
+
+template<int k_max_nn, class Real_, class PointContainer_>
+AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::AuctionOracleStupidSparseRestricted(const PointContainer_& _bidders,
+ const PointContainer_& _items,
+ const AuctionParams<Real_>& params) :
+ AuctionOracleBase<Real_, PointContainer_>(_bidders, _items, params),
+ admissible_items_(_bidders.size(), std::vector<size_t>()),
+ heap_handles_indices_(_items.size(), k_invalid_index),
+ top_diag_lookup_(_items.size(), k_invalid_index)
+{
+ // initialize admissible edges
+ std::vector<size_t> kdtree_items_(_items.size(), k_invalid_index);
+ std::vector<DnnPoint> dnn_points_;
+ std::vector<DnnPoint*> dnn_point_handles_;
+ size_t dnn_item_idx { 0 };
+ size_t true_idx { 0 };
+ dnn_points_.reserve(this->items.size());
+ // store normal items in kd-tree
+ for(const auto& g : this->items) {
+ if (g.is_normal() ) {
+ kdtree_items_[true_idx] = dnn_item_idx;
+ // index of items is id of dnn-point
+ DnnPoint p(true_idx);
+ p[0] = g.getRealX();
+ p[1] = g.getRealY();
+ dnn_points_.push_back(p);
+ assert(dnn_item_idx == dnn_points_.size() - 1);
+ dnn_item_idx++;
+ }
+ true_idx++;
+ }
+ assert(dnn_points_.size() < _items.size() );
+ for(size_t i = 0; i < dnn_points_.size(); ++i) {
+ dnn_point_handles_.push_back(&dnn_points_[i]);
+ }
+ DnnTraits traits;
+ traits.internal_p = params.internal_p;
+ dnn::KDTree<DnnTraits> kdtree_(traits, dnn_point_handles_, params.wasserstein_power);
+
+ // loop over normal bidders, find nearest neighbours
+ size_t bidder_idx = 0;
+ for(const auto& b : this->bidders) {
+ if (b.is_normal()) {
+ admissible_items_[bidder_idx].reserve(k_max_nn);
+ DnnPoint bidder_dnn;
+ bidder_dnn[0] = b.getRealX();
+ bidder_dnn[1] = b.getRealY();
+ auto nearest_neighbours = kdtree_.findK(bidder_dnn, k_max_nn);
+ assert(nearest_neighbours.size() == k_max_nn);
+ for(const auto& x : nearest_neighbours) {
+ admissible_items_[bidder_idx].push_back(x.p->id());
+ }
+ }
+ bidder_idx++;
+ }
+
+ size_t handle_idx {0};
+ for(size_t item_idx = 0; item_idx < _items.size(); ++item_idx) {
+ if (this->items[item_idx].is_diagonal()) {
+ heap_handles_indices_[item_idx] = handle_idx++;
+ diag_heap_handles_.push_back(diag_items_heap_.push(std::make_pair(item_idx, 0.0)));
+ }
+ }
+ max_val_ = 3*getFurthestDistance3Approx<>(_bidders, _items, params.internal_p);
+ max_val_ = std::pow(max_val_, params.wasserstein_power);
+}
+
+
+template<int k_max_nn, class Real_, class PointContainer_>
+bool AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::is_in_top_diag_indices(const size_t item_idx) const
+{
+ return top_diag_lookup_[item_idx] != k_invalid_index;
+}
+
+
+template<int k_max_nn, class Real_, class PointContainer_>
+void AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::add_top_diag_index(const size_t item_idx)
+{
+ assert(find(top_diag_indices_.begin(), top_diag_indices_.end(), item_idx) == top_diag_indices_.end());
+ assert(this->items[item_idx].is_diagonal());
+
+ top_diag_indices_.push_back(item_idx);
+ top_diag_lookup_[item_idx] = top_diag_indices_.size() - 1;
+}
+
+template<int k_max_nn, class Real_, class PointContainer_>
+void AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::remove_top_diag_index(const size_t item_idx)
+{
+ if (top_diag_indices_.size() > 1) {
+ // remove item_idx from top_diag_indices after swapping
+ // it with the last element, update index lookup appropriately
+ auto old_index = top_diag_lookup_[item_idx];
+ auto end_element = top_diag_indices_.back();
+ std::swap(top_diag_indices_[old_index], top_diag_indices_.back());
+ top_diag_lookup_[end_element] = old_index;
+ }
+
+ top_diag_indices_.pop_back();
+ top_diag_lookup_[item_idx] = k_invalid_index;
+ if (top_diag_indices_.size() < 2) {
+ recompute_second_best_diag();
+ }
+ best_diagonal_items_computed_ = not top_diag_indices_.empty();
+ reset_top_diag_counter();
+}
+
+
+template<int k_max_nn, class Real_, class PointContainer_>
+void AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::increment_top_diag_counter()
+{
+ assert(top_diag_counter_ >= 0 and top_diag_counter_ < top_diag_indices_.size());
+
+ ++top_diag_counter_;
+ if (top_diag_counter_ >= top_diag_indices_.size()) {
+ top_diag_counter_ -= top_diag_indices_.size();
+ }
+
+ assert(top_diag_counter_ >= 0 and top_diag_counter_ < top_diag_indices_.size());
+}
+
+
+template<int k_max_nn, class Real_, class PointContainer_>
+void AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::reset_top_diag_counter()
+{
+ top_diag_counter_ = 0;
+}
+
+template<int k_max_nn, class Real_, class PointContainer_>
+void AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::recompute_top_diag_items(bool hard)
+{
+ assert(hard or top_diag_indices_.empty());
+
+ if (hard) {
+ std::fill(top_diag_lookup_.begin(), top_diag_lookup_.end(), k_invalid_index);
+ top_diag_indices_.clear();
+ }
+
+ auto top_diag_iter = diag_items_heap_.ordered_begin();
+ best_diagonal_item_value_ = top_diag_iter->second;
+ add_top_diag_index(top_diag_iter->first);
+
+ ++top_diag_iter;
+
+ // traverse the heap while we see the same value
+ while(top_diag_iter != diag_items_heap_.ordered_end()) {
+ if ( top_diag_iter->second != best_diagonal_item_value_) {
+ break;
+ } else {
+ add_top_diag_index(top_diag_iter->first);
+ }
+ ++top_diag_iter;
+ }
+
+ recompute_second_best_diag();
+
+ best_diagonal_items_computed_ = true;
+ reset_top_diag_counter();
+}
+
+template<int k_max_nn, class Real_, class PointContainer_>
+typename AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::DebugOptimalBidR
+AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::get_optimal_bid_debug(IdxType bidder_idx) const
+{
+ DebugOptimalBidR result;
+ throw std::runtime_error("Not implemented");
+ return result;
+}
+
+
+template<int k_max_nn, class Real_, class PointContainer_>
+IdxValPair<Real_> AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::get_optimal_bid(IdxType bidder_idx)
+{
+ auto bidder = this->bidders[bidder_idx];
+
+ // corresponding point is always considered as a candidate
+ // if bidder is a diagonal point, proj_item is a normal point,
+ // and vice versa.
+
+ size_t best_item_idx { k_invalid_index };
+ size_t second_best_item_idx { k_invalid_index };
+ size_t best_diagonal_item_idx { k_invalid_index };
+ Real best_item_value;
+ Real second_best_item_value;
+
+
+ size_t proj_item_idx = bidder_idx;
+ assert( 0 <= proj_item_idx and proj_item_idx < this->items.size() );
+ assert(this->items[proj_item_idx].type != bidder.type);
+ Real proj_item_value = this->get_value_for_bidder(bidder_idx, proj_item_idx);
+
+ if (bidder.is_diagonal()) {
+ // for diagonal bidder the only normal point has already been added
+ // the other 2 candidates are diagonal items only, get from the heap
+ // with prices
+
+ if (not best_diagonal_items_computed_) {
+ recompute_top_diag_items();
+ }
+
+ best_diagonal_item_idx = top_diag_indices_[top_diag_counter_];
+ increment_top_diag_counter();
+
+ if ( proj_item_value < best_diagonal_item_value_) {
+ best_item_idx = proj_item_idx;
+ best_item_value = proj_item_value;
+ second_best_item_value = best_diagonal_item_value_;
+ second_best_item_idx = best_diagonal_item_idx;
+ } else if (proj_item_value < second_best_diagonal_item_value_) {
+ best_item_idx = best_diagonal_item_idx;
+ best_item_value = best_diagonal_item_value_;
+ second_best_item_value = proj_item_value;
+ second_best_item_idx = proj_item_idx;
+ } else {
+ best_item_idx = best_diagonal_item_idx;
+ best_item_value = best_diagonal_item_value_;
+ second_best_item_value = second_best_diagonal_item_value_;
+ second_best_item_idx = second_best_diagonal_item_idx_;
+ }
+ } else {
+
+ size_t best_normal_item_idx { k_invalid_index };
+ size_t second_best_normal_item_idx { k_invalid_index };
+ Real best_normal_item_value { std::numeric_limits<Real>::max() };
+ Real second_best_normal_item_value { std::numeric_limits<Real>::max() };
+
+ // find best item
+ for(const auto curr_item_idx : admissible_items_[bidder_idx]) {
+ auto curr_item_value = this->get_value_for_bidder(bidder_idx, curr_item_idx);
+ if (curr_item_value < best_normal_item_value) {
+ best_normal_item_idx = curr_item_idx;
+ best_normal_item_value = curr_item_value;
+ }
+ }
+
+ // find second-best item
+ for(const auto curr_item_idx : admissible_items_[bidder_idx]) {
+ if (curr_item_idx == best_normal_item_idx) {
+ continue;
+ }
+ auto curr_item_value = this->get_value_for_bidder(bidder_idx, curr_item_idx);
+ if (curr_item_value < second_best_normal_item_value) {
+ second_best_normal_item_idx = curr_item_idx;
+ second_best_normal_item_value = curr_item_value;
+ }
+ }
+
+ if ( proj_item_value < best_normal_item_value) {
+ best_item_idx = proj_item_idx;
+ increment_top_diag_counter();
+ best_item_value = proj_item_value;
+ second_best_item_value = best_normal_item_value;
+ } else if (proj_item_value < second_best_normal_item_value) {
+ best_item_idx = best_normal_item_idx;
+ best_item_value = best_normal_item_value;
+ second_best_item_value = proj_item_value;
+ } else {
+ best_item_idx = best_normal_item_idx;
+ best_item_value = best_normal_item_value;
+ second_best_item_value = second_best_normal_item_value;
+ }
+ }
+
+ IdxValPair<Real> result;
+
+ assert( second_best_item_value >= best_item_value );
+
+ result.first = best_item_idx;
+ result.second = ( second_best_item_value - best_item_value ) + this->prices[best_item_idx] + this->epsilon;
+
+ return result;
+}
+
+template<int k_max_nn, class Real_, class PointContainer_>
+void AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::recompute_second_best_diag()
+{
+ if (top_diag_indices_.size() > 1) {
+ second_best_diagonal_item_value_ = best_diagonal_item_value_;
+ second_best_diagonal_item_idx_ = top_diag_indices_[0];
+ } else {
+ if (diag_items_heap_.size() == 1) {
+ second_best_diagonal_item_value_ == std::numeric_limits<Real>::max();
+ second_best_diagonal_item_idx_ = k_invalid_index;
+ } else {
+ auto diag_iter = diag_items_heap_.ordered_begin();
+ ++diag_iter;
+ second_best_diagonal_item_value_ = diag_iter->second;
+ second_best_diagonal_item_idx_ = diag_iter->first;
+ }
+ }
+}
+
+
+template<int k_max_nn, class Real_, class PointContainer_>
+void AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::set_price(IdxType item_idx,
+ Real new_price,
+ const bool update_diag)
+{
+ assert(this->prices.size() == this->items.size());
+ assert( 0 < diag_heap_handles_.size() and diag_heap_handles_.size() <= this->items.size());
+ // adjust_prices decreases prices,
+ // also this variable must be true in reverse phases of FR-auction
+ bool item_goes_down = new_price > this->prices[item_idx];
+
+ this->prices[item_idx] = new_price;
+ if ( this->items[item_idx].is_diagonal() ) {
+ assert(diag_heap_handles_.size() > heap_handles_indices_.at(item_idx));
+ if (item_goes_down) {
+ diag_items_heap_.decrease(diag_heap_handles_[heap_handles_indices_[item_idx]], std::make_pair(item_idx, new_price));
+ } else {
+ diag_items_heap_.increase(diag_heap_handles_[heap_handles_indices_[item_idx]], std::make_pair(item_idx, new_price));
+ }
+ if (update_diag) {
+ // Update top_diag_indices_ only if necessary:
+ // normal bidders take their projections, which might not be on top
+ // also, set_price is called by adjust_prices, and we may have already
+ // removed the item from top_diag
+ if (is_in_top_diag_indices(item_idx)) {
+ remove_top_diag_index(item_idx);
+ }
+
+ if (item_idx == second_best_diagonal_item_idx_) {
+ recompute_second_best_diag();
+ }
+ }
+ }
+}
+
+
+template<int k_max_nn, class Real_, class PointContainer_>
+void AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::adjust_prices(Real delta)
+{
+ if (delta == 0.0)
+ return;
+
+ for(auto& p : this->prices) {
+ p -= delta;
+ }
+
+ bool price_goes_up = delta < 0;
+
+ for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ if (this->items[item_idx].is_diagonal()) {
+ auto new_price = this->prices[item_idx];
+ if (price_goes_up) {
+ diag_items_heap_.decrease(diag_heap_handles_[heap_handles_indices_[item_idx]], std::make_pair(item_idx, new_price));
+ } else {
+ diag_items_heap_.increase(diag_heap_handles_[heap_handles_indices_[item_idx]], std::make_pair(item_idx, new_price));
+ }
+ }
+ }
+ best_diagonal_item_value_ -= delta;
+ second_best_diagonal_item_value_ -= delta;
+}
+
+template<int k_max_nn, class Real_, class PointContainer_>
+void AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::adjust_prices()
+{
+ auto pr_begin = this->prices.begin();
+ auto pr_end = this->prices.end();
+ Real min_price = *(std::min_element(pr_begin, pr_end));
+ adjust_prices(min_price);
+}
+
+template<int k_max_nn, class Real_, class PointContainer_>
+size_t AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::get_heap_top_size() const
+{
+ return top_diag_indices_.size();
+}
+
+template<int k_max_nn, class Real_, class PointContainer_>
+std::pair<Real_, Real_> AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::get_minmax_price() const
+{
+ auto r = std::minmax_element(this->prices.begin(), this->prices.end());
+ return std::make_pair(*r.first, *r.second);
+}
+
+template<int k_max_nn, class Real_, class PointContainer_>
+void AuctionOracleStupidSparseRestricted<k_max_nn, Real_, PointContainer_>::sanity_check()
+{
+#ifdef DEBUG_STUPID_SPARSE_RESTR_ORACLE
+
+ assert(admissible_items_.size() == this->bidders.size());
+
+ for(size_t bidder_idx = 0; bidder_idx < this->bidders.size(); ++bidder_idx) {
+ if (this->bidders[bidder_idx].is_normal()) {
+ assert(admissible_items_[bidder_idx].size() == k_max_nn);
+ } else {
+ assert(admissible_items_[bidder_idx].size() == 0);
+ }
+ }
+
+ if (best_diagonal_items_computed_) {
+ std::vector<Real> diag_items_price_vec;
+ diag_items_price_vec.reserve(this->items.size());
+
+ for(size_t item_idx = 0; item_idx < this->items.size(); ++item_idx) {
+ if (this->items.at(item_idx).is_diagonal()) {
+ diag_items_price_vec.push_back(this->prices.at(item_idx));
+ } else {
+ diag_items_price_vec.push_back(std::numeric_limits<Real>::max());
+ }
+ }
+
+ auto best_iter = std::min_element(diag_items_price_vec.begin(), diag_items_price_vec.end());
+ assert(best_iter != diag_items_price_vec.end());
+ Real true_best_diag_value = *best_iter;
+ size_t true_best_diag_idx = best_iter - diag_items_price_vec.begin();
+ assert(true_best_diag_value != std::numeric_limits<Real>::max());
+
+ Real true_second_best_diag_value = std::numeric_limits<Real>::max();
+ size_t true_second_best_diag_idx = k_invalid_index;
+ for(size_t item_idx = 0; item_idx < diag_items_price_vec.size(); ++item_idx) {
+ if (this->items.at(item_idx).is_normal()) {
+ assert(top_diag_lookup_.at(item_idx) == k_invalid_index);
+ continue;
+ }
+
+ auto i_iter = std::find(top_diag_indices_.begin(), top_diag_indices_.end(), item_idx);
+ if (diag_items_price_vec.at(item_idx) == true_best_diag_value) {
+ assert(i_iter != top_diag_indices_.end());
+ assert(top_diag_lookup_.at(item_idx) == i_iter - top_diag_indices_.begin());
+ } else {
+ assert(top_diag_lookup_.at(item_idx) == k_invalid_index);
+ assert(i_iter == top_diag_indices_.end());
+ }
+
+ if (item_idx == true_best_diag_idx) {
+ continue;
+ }
+ if (diag_items_price_vec.at(item_idx) < true_second_best_diag_value) {
+ true_second_best_diag_value = diag_items_price_vec.at(item_idx);
+ true_second_best_diag_idx = item_idx;
+ }
+ }
+
+ if (true_best_diag_value != best_diagonal_item_value_) {
+ std::cerr << *this;
+ }
+
+ assert(true_best_diag_value == best_diagonal_item_value_);
+
+ assert(true_second_best_diag_idx != k_invalid_index);
+ assert(true_second_best_diag_value == second_best_diagonal_item_value_);
+ }
+#endif
+}
+
+
+} // ws
+} // hera
+
+#endif
diff --git a/wasserstein/include/auction_runner_fr.h b/wasserstein/include/auction_runner_fr.h
new file mode 100644
index 0000000..0c67b65
--- /dev/null
+++ b/wasserstein/include/auction_runner_fr.h
@@ -0,0 +1,272 @@
+/*
+
+Copyright (c) 2016, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_RUNNER_FR_H
+#define AUCTION_RUNNER_FR_H
+
+#define ORDERED_BY_PERSISTENCE
+
+#include <unordered_set>
+
+#include "auction_oracle.h"
+
+namespace hera {
+namespace ws {
+
+// the two parameters that you can tweak in auction algorithm are:
+// 1. epsilon_common_ratio
+// 2. max_num_phases
+
+template<class RealType_, class AuctionOracle_ = AuctionOracleKDTreeRestricted<RealType_>> // alternatively: AuctionOracleLazyHeap --- TODO
+class AuctionRunnerFR {
+public:
+
+ using Real = RealType_;
+ using AuctionOracle = AuctionOracle_;
+ using DgmPoint = DiagramPoint<Real>;
+ using DgmPointVec = std::vector<DgmPoint>;
+ using IdxValPairR = IdxValPair<Real>;
+
+ const Real k_lowest_bid_value = -(std::numeric_limits<Real>::max() - 1); // all bid values must be positive
+
+
+ AuctionRunnerFR(const std::vector<DgmPoint>& A,
+ const std::vector<DgmPoint>& B,
+ const Real q,
+ const Real _delta,
+ const Real _internal_p,
+ const Real _initial_epsilon = 0.0,
+ const Real _eps_factor = 5.0,
+ const int _max_num_phases = std::numeric_limits<int>::max(),
+ const Real _gamma_threshold = 0.0,
+ const size_t _max_bids_per_round = std::numeric_limits<size_t>::max(),
+ const std::string& _log_filename_prefix = "");
+
+ void set_epsilon(Real new_val);
+ Real get_epsilon() const { return epsilon; }
+ void run_auction();
+ Real get_wasserstein_distance();
+ Real get_wasserstein_cost();
+ Real get_relative_error(const bool debug_output = false) const;
+ bool phase_can_be_final() const;
+private:
+ // private data
+ std::vector<DgmPoint> bidders, items;
+ const size_t num_bidders;
+ const size_t num_items;
+ std::vector<IdxType> items_to_bidders;
+ std::vector<IdxType> bidders_to_items;
+ Real wasserstein_power;
+ Real epsilon;
+ Real delta;
+ Real internal_p;
+ Real initial_epsilon;
+ const Real epsilon_common_ratio; // next epsilon = current epsilon / epsilon_common_ratio
+ Real cumulative_epsilon_factor { 1.0 };
+ const int max_num_phases; // maximal number of phases of epsilon-scaling
+ bool is_forward { true }; // to use in distributed version only
+ Real weight_adj_const;
+ Real wasserstein_cost;
+ std::vector<IdxValPairR> forward_bid_table;
+ std::vector<IdxValPairR> reverse_bid_table;
+ // to get the 2 best items
+ AuctionOracle forward_oracle;
+ AuctionOracle reverse_oracle;
+ std::unordered_set<size_t> unassigned_bidders;
+ std::unordered_set<size_t> unassigned_items;
+ std::unordered_set<size_t> items_with_bids;
+ std::unordered_set<size_t> bidders_with_bids;
+
+#ifdef ORDERED_BY_PERSISTENCE
+ // to process unassigned by persistence
+ size_t batch_size;
+ using RealIdxPair = std::pair<Real, size_t>;
+ std::set<RealIdxPair, std::greater<RealIdxPair>> unassigned_bidders_by_persistence;
+ std::set<RealIdxPair, std::greater<RealIdxPair>> unassigned_items_by_persistence;
+#endif
+
+
+ // to imitate Gauss-Seidel
+ const size_t max_bids_per_round;
+
+ // to stop earlier in the last phase
+ const Real total_items_persistence;
+ const Real total_bidders_persistence;
+ Real partial_cost;
+ Real unassigned_bidders_persistence;
+ Real unassigned_items_persistence;
+ Real gamma_threshold;
+ size_t unassigned_threshold;
+
+ bool is_distance_computed { false };
+ int num_rounds { 0 };
+ int num_rounds_non_cumulative { 0 };
+ int num_phase { 0 };
+
+
+ size_t num_diag_items { 0 };
+ size_t num_normal_items { 0 };
+ size_t num_diag_bidders { 0 };
+ size_t num_normal_bidders { 0 };
+
+
+
+ // private methods
+ void assign_forward(const IdxType item_idx, const IdxType bidder_idx);
+ void assign_reverse(const IdxType item_idx, const IdxType bidder_idx);
+ void assign_to_best_bidder(const IdxType item_idx);
+ void assign_to_best_item(const IdxType bidder_idx);
+ void clear_forward_bid_table();
+ void clear_reverse_bid_table();
+ void assign_diag_to_diag();
+ void run_auction_phases(const int max_num_phases, const Real _initial_epsilon);
+ void run_auction_phase();
+ void run_forward_auction_phase();
+ void run_reverse_auction_phase();
+ void submit_forward_bid(IdxType bidder_idx, const IdxValPairR& bid);
+ void submit_reverse_bid(IdxType item_idx, const IdxValPairR& bid);
+ void flush_assignment();
+ Real get_item_bidder_cost(const size_t item_idx, const size_t bidder_idx) const;
+ Real get_cost_to_diagonal(const DgmPoint& pt) const;
+ Real get_gamma() const;
+
+ template<class Range>
+ void run_forward_bidding_step(const Range& r);
+
+ template<class Range>
+ void run_reverse_bidding_step(const Range& r);
+
+ void add_unassigned_bidder(const size_t bidder_idx);
+ void add_unassigned_item(const size_t item_idx);
+ void remove_unassigned_bidder(const size_t bidder_idx);
+ void remove_unassigned_item(const size_t item_idx);
+
+ bool is_item_diagonal(const size_t item_idx) const { return item_idx < num_diag_items; }
+ bool is_item_normal(const size_t item_idx) const { return not is_item_diagonal(item_idx); }
+ bool is_bidder_diagonal(const size_t bidder_idx) const { return bidder_idx >= num_normal_bidders; }
+ bool is_bidder_normal(const size_t bidder_idx) const { return not is_bidder_diagonal(bidder_idx); }
+
+ size_t num_forward_bids_submitted { 0 };
+ size_t num_reverse_bids_submitted { 0 };
+
+ void decrease_epsilon();
+ // stopping criteria
+ bool continue_forward(const size_t, const size_t);
+ bool continue_reverse(const size_t, const size_t);
+ bool continue_phase();
+
+
+
+ // for debug only
+ void sanity_check();
+ void check_epsilon_css();
+ void print_debug();
+ void print_matching();
+
+ std::string log_filename_prefix;
+ const Real k_max_relative_error = 2.0; // if relative error cannot be estimated or is too large, use this value
+ void reset_round_stat(); // empty, if logging is disable
+ void reset_phase_stat();
+
+ std::unordered_set<size_t> never_assigned_bidders;
+ std::unordered_set<size_t> never_assigned_items;
+
+#ifdef LOG_AUCTION
+ std::unordered_set<size_t> unassigned_normal_bidders;
+ std::unordered_set<size_t> unassigned_diag_bidders;
+
+ std::unordered_set<size_t> unassigned_normal_items;
+ std::unordered_set<size_t> unassigned_diag_items;
+
+
+ size_t all_assigned_round { 0 };
+ size_t all_assigned_round_found { false };
+
+ int num_forward_rounds_non_cumulative { 0 };
+ int num_forward_rounds { 0 };
+
+ int num_reverse_rounds_non_cumulative { 0 };
+ int num_reverse_rounds { 0 };
+
+ // all per-round vars are non-cumulative
+
+ // forward rounds
+ int num_normal_forward_bids_submitted { 0 };
+ int num_diag_forward_bids_submitted { 0 };
+
+ int num_forward_diag_to_diag_assignments { 0 };
+ int num_forward_diag_to_normal_assignments { 0 };
+ int num_forward_normal_to_diag_assignments { 0 };
+ int num_forward_normal_to_normal_assignments { 0 };
+
+ int num_forward_diag_from_diag_thefts { 0 };
+ int num_forward_diag_from_normal_thefts { 0 };
+ int num_forward_normal_from_diag_thefts { 0 };
+ int num_forward_normal_from_normal_thefts { 0 };
+
+ // reverse rounds
+ int num_normal_reverse_bids_submitted { 0 };
+ int num_diag_reverse_bids_submitted { 0 };
+
+ int num_reverse_diag_to_diag_assignments { 0 };
+ int num_reverse_diag_to_normal_assignments { 0 };
+ int num_reverse_normal_to_diag_assignments { 0 };
+ int num_reverse_normal_to_normal_assignments { 0 };
+
+ int num_reverse_diag_from_diag_thefts { 0 };
+ int num_reverse_diag_from_normal_thefts { 0 };
+ int num_reverse_normal_from_diag_thefts { 0 };
+ int num_reverse_normal_from_normal_thefts { 0 };
+
+ // price change statistics
+ std::vector<std::vector<size_t>> forward_price_change_cnt_vec;
+ std::vector<std::vector<size_t>> reverse_price_change_cnt_vec;
+
+ size_t parallel_threshold = 5000;
+ int num_parallelizable_rounds { 0 };
+ int num_parallelizable_forward_rounds { 0 };
+ int num_parallelizable_reverse_rounds { 0 };
+
+ int num_parallel_bids { 0 };
+ int num_total_bids { 0 };
+
+ int num_parallel_assignments { 0 };
+ int num_total_assignments { 0 };
+#endif
+
+};
+
+
+
+} // ws
+} // hera
+
+#include "auction_runner_fr.hpp"
+
+#undef ORDERED_BY_PERSISTENCE
+#endif
diff --git a/wasserstein/include/auction_runner_fr.hpp b/wasserstein/include/auction_runner_fr.hpp
new file mode 100644
index 0000000..b0b65d0
--- /dev/null
+++ b/wasserstein/include/auction_runner_fr.hpp
@@ -0,0 +1,1208 @@
+/*
+
+Copyright (c) 2016, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_RUNNER_FR_HPP
+#define AUCTION_RUNNER_FR_HPP
+
+#include <cassert>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+#include "def_debug_ws.h"
+
+#include "auction_runner_fr.h"
+
+#ifdef FOR_R_TDA
+#include "Rcpp.h"
+#undef DEBUG_FR_AUCTION
+#endif
+
+
+namespace hera {
+namespace ws {
+
+
+// *****************************
+// AuctionRunnerFR
+// *****************************
+
+template<class R, class AO>
+AuctionRunnerFR<R, AO>::AuctionRunnerFR(const std::vector<DgmPoint>& A,
+ const std::vector<DgmPoint>& B,
+ const Real q,
+ const Real _delta,
+ const Real _internal_p,
+ const Real _initial_epsilon,
+ const Real _eps_factor,
+ const int _max_num_phases,
+ const Real _gamma_threshold,
+ const size_t _max_bids_per_round,
+ const std::string& _log_filename_prefix
+ ) :
+ bidders(A),
+ items(B),
+ num_bidders(A.size()),
+ num_items(A.size()),
+ items_to_bidders(A.size(), k_invalid_index),
+ bidders_to_items(A.size(), k_invalid_index),
+ wasserstein_power(q),
+ delta(_delta),
+ internal_p(_internal_p),
+ initial_epsilon(_initial_epsilon),
+ epsilon_common_ratio(_eps_factor == 0.0 ? 5.0 : _eps_factor),
+ max_num_phases(_max_num_phases),
+ forward_bid_table(A.size(), std::make_pair(k_invalid_index, k_lowest_bid_value) ),
+ reverse_bid_table(B.size(), std::make_pair(k_invalid_index, k_lowest_bid_value) ),
+ forward_oracle(bidders, items, q, _internal_p),
+ reverse_oracle(items, bidders, q, _internal_p),
+ max_bids_per_round(_max_bids_per_round),
+ total_items_persistence(std::accumulate(items.begin(),
+ items.end(),
+ R(0.0),
+ [_internal_p, q](const Real& ps, const DgmPoint& item)
+ { return ps + std::pow(item.persistence_lp(_internal_p), q); }
+ )),
+ total_bidders_persistence(std::accumulate(bidders.begin(),
+ bidders.end(),
+ R(0.0),
+ [_internal_p, q](const Real& ps, const DgmPoint& bidder)
+ { return ps + std::pow(bidder.persistence_lp(_internal_p), q); }
+ )),
+ partial_cost(0.0),
+ unassigned_bidders_persistence(total_bidders_persistence),
+ unassigned_items_persistence(total_items_persistence),
+ gamma_threshold(_gamma_threshold),
+ log_filename_prefix(_log_filename_prefix)
+{
+ assert(A.size() == B.size());
+ for(const auto& p : bidders) {
+ if (p.is_normal()) {
+ num_normal_bidders++;
+ num_diag_items++;
+ } else {
+ num_normal_items++;
+ num_diag_bidders++;
+ }
+ }
+
+#ifdef ORDERED_BY_PERSISTENCE
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ unassigned_bidders_by_persistence.insert(std::make_pair(bidders[bidder_idx].persistence_lp(1.0), bidder_idx));
+ }
+
+ for(size_t item_idx = 0; item_idx < num_items; ++item_idx) {
+ unassigned_items_by_persistence.insert(std::make_pair(items[item_idx].persistence_lp(1.0), item_idx));
+ }
+#endif
+
+ // for experiments
+ unassigned_threshold = bidders.size() / 200;
+ unassigned_threshold = 0;
+
+#ifdef ORDERED_BY_PERSISTENCE
+ batch_size = 5000;
+#endif
+}
+
+template<class R, class AO>
+typename AuctionRunnerFR<R, AO>::Real
+AuctionRunnerFR<R, AO>::get_cost_to_diagonal(const DgmPoint& pt) const
+{
+ if (1.0 == wasserstein_power) {
+ return pt.persistence_lp(internal_p);
+ } else {
+ return std::pow(pt.persistence_lp(internal_p), wasserstein_power);
+ }
+}
+
+
+template<class R, class AO>
+typename AuctionRunnerFR<R, AO>::Real
+AuctionRunnerFR<R, AO>::get_gamma() const
+{
+ if (1.0 == wasserstein_power) {
+ return unassigned_items_persistence + unassigned_bidders_persistence;
+ } else {
+ return std::pow(unassigned_items_persistence + unassigned_bidders_persistence,
+ 1.0 / wasserstein_power);
+ }
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::reset_phase_stat()
+{
+ num_rounds_non_cumulative = 0;
+#ifdef LOG_AUCTION
+ num_parallelizable_rounds = 0;
+ num_parallelizable_forward_rounds = 0;
+ num_parallelizable_reverse_rounds = 0;
+ num_forward_rounds_non_cumulative = 0;
+ num_reverse_rounds_non_cumulative = 0;
+#endif
+}
+
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::reset_round_stat()
+{
+ num_forward_bids_submitted = 0;
+ num_reverse_bids_submitted = 0;
+#ifdef LOG_AUCTION
+ num_normal_forward_bids_submitted = 0;
+ num_diag_forward_bids_submitted = 0;
+
+ num_forward_diag_to_diag_assignments = 0;
+ num_forward_diag_to_normal_assignments = 0;
+ num_forward_normal_to_diag_assignments = 0;
+ num_forward_normal_to_normal_assignments = 0;
+
+ num_forward_diag_from_diag_thefts = 0;
+ num_forward_diag_from_normal_thefts = 0;
+ num_forward_normal_from_diag_thefts = 0;
+ num_forward_normal_from_normal_thefts = 0;
+
+ // reverse rounds
+ num_normal_reverse_bids_submitted = 0;
+ num_diag_reverse_bids_submitted = 0;
+
+ num_reverse_diag_to_diag_assignments = 0;
+ num_reverse_diag_to_normal_assignments = 0;
+ num_reverse_normal_to_diag_assignments = 0;
+ num_reverse_normal_to_normal_assignments = 0;
+
+ num_reverse_diag_from_diag_thefts = 0;
+ num_reverse_diag_from_normal_thefts = 0;
+ num_reverse_normal_from_diag_thefts = 0;
+ num_reverse_normal_from_normal_thefts = 0;
+#endif
+}
+
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::assign_forward(IdxType item_idx, IdxType bidder_idx)
+{
+ sanity_check();
+ // only unassigned bidders submit bids
+ assert(bidders_to_items[bidder_idx] == k_invalid_index);
+
+ IdxType old_item_owner = items_to_bidders[item_idx];
+
+ // set new owner
+ bidders_to_items[bidder_idx] = item_idx;
+ items_to_bidders[item_idx] = bidder_idx;
+
+ // remove bidder and item from the sets of unassigned bidders/items
+ remove_unassigned_bidder(bidder_idx);
+
+ if (k_invalid_index != old_item_owner) {
+ // old owner of item becomes unassigned
+ bidders_to_items[old_item_owner] = k_invalid_index;
+ add_unassigned_bidder(old_item_owner);
+ // existing edge was removed, decrease partial_cost
+ partial_cost -= get_item_bidder_cost(item_idx, old_item_owner);
+ } else {
+ // item was unassigned before
+ remove_unassigned_item(item_idx);
+ }
+
+ // new edge was added to matching, increase partial cost
+ partial_cost += get_item_bidder_cost(item_idx, bidder_idx);
+
+#ifdef LOG_AUCTION
+
+ if (unassigned_bidders.size() > parallel_threshold) {
+ num_parallel_assignments++;
+ }
+ num_total_assignments++;
+
+
+ int it_d = is_item_diagonal(item_idx);
+ int b_d = is_bidder_diagonal(bidder_idx);
+ // 2 - None
+ int old_d = ( k_invalid_index == old_item_owner ) ? 2 : is_bidder_diagonal(old_item_owner);
+ int key = 100 * old_d + 10 * b_d + it_d;
+ switch(key) {
+ case 211 : num_forward_diag_to_diag_assignments++;
+ break;
+ case 210 : num_forward_diag_to_normal_assignments++;
+ break;
+ case 201 : num_forward_normal_to_diag_assignments++;
+ break;
+ case 200 : num_forward_normal_to_normal_assignments++;
+ break;
+
+ case 111 : num_forward_diag_to_diag_assignments++;
+ num_forward_diag_from_diag_thefts++;
+ break;
+ case 110 : num_forward_diag_to_normal_assignments++;
+ num_forward_diag_from_diag_thefts++;
+ break;
+ break;
+ case 101 : num_forward_normal_to_diag_assignments++;
+ num_forward_normal_from_diag_thefts++;
+ break;
+ break;
+ case 100 : num_forward_normal_to_normal_assignments++;
+ num_forward_normal_from_diag_thefts++;
+ break;
+
+ case 11 : num_forward_diag_to_diag_assignments++;
+ num_forward_diag_from_normal_thefts++;
+ break;
+ case 10 : num_forward_diag_to_normal_assignments++;
+ num_forward_diag_from_normal_thefts++;
+ break;
+ break;
+ case 1 : num_forward_normal_to_diag_assignments++;
+ num_forward_normal_from_normal_thefts++;
+ break;
+ break;
+ case 0 : num_forward_normal_to_normal_assignments++;
+ num_forward_normal_from_normal_thefts++;
+ break;
+ default : std::cerr << "key = " << key << std::endl;
+ throw std::runtime_error("Bug in logging, wrong key");
+ break;
+ }
+#endif
+
+ sanity_check();
+}
+
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::assign_reverse(IdxType item_idx, IdxType bidder_idx)
+{
+ // only unassigned items submit bids in reverse phase
+ assert(items_to_bidders[item_idx] == k_invalid_index);
+
+ IdxType old_bidder_owner = bidders_to_items[bidder_idx];
+
+ // set new owner
+ bidders_to_items[bidder_idx] = item_idx;
+ items_to_bidders[item_idx] = bidder_idx;
+
+ // remove bidder and item from the sets of unassigned bidders/items
+ remove_unassigned_item(item_idx);
+
+ if (k_invalid_index != old_bidder_owner) {
+ // old owner of item becomes unassigned
+ items_to_bidders[old_bidder_owner] = k_invalid_index;
+ add_unassigned_item(old_bidder_owner);
+ // existing edge was removed, decrease partial_cost
+ partial_cost -= get_item_bidder_cost(old_bidder_owner, bidder_idx);
+ } else {
+ // item was unassigned before
+ remove_unassigned_bidder(bidder_idx);
+ }
+
+ // new edge was added to matching, increase partial cost
+ partial_cost += get_item_bidder_cost(item_idx, bidder_idx);
+
+#ifdef LOG_AUCTION
+ if (unassigned_items.size() > parallel_threshold) {
+ num_parallel_assignments++;
+ }
+ num_total_assignments++;
+
+ int it_d = is_item_diagonal(item_idx);
+ int b_d = is_bidder_diagonal(bidder_idx);
+ // 2 - None
+ int old_d = (k_invalid_index == old_bidder_owner) ? 2 : is_item_diagonal(old_bidder_owner);
+ int key = 100 * old_d + 10 * it_d + b_d;
+ switch(key) {
+ case 211 : num_reverse_diag_to_diag_assignments++;
+ break;
+ case 210 : num_reverse_diag_to_normal_assignments++;
+ break;
+ case 201 : num_reverse_normal_to_diag_assignments++;
+ break;
+ case 200 : num_reverse_normal_to_normal_assignments++;
+ break;
+
+ case 111 : num_reverse_diag_to_diag_assignments++;
+ num_reverse_diag_from_diag_thefts++;
+ break;
+ case 110 : num_reverse_diag_to_normal_assignments++;
+ num_reverse_diag_from_diag_thefts++;
+ break;
+ break;
+ case 101 : num_reverse_normal_to_diag_assignments++;
+ num_reverse_normal_from_diag_thefts++;
+ break;
+ break;
+ case 100 : num_reverse_normal_to_normal_assignments++;
+ num_reverse_normal_from_diag_thefts++;
+ break;
+
+ case 11 : num_reverse_diag_to_diag_assignments++;
+ num_reverse_diag_from_normal_thefts++;
+ break;
+ case 10 : num_reverse_diag_to_normal_assignments++;
+ num_reverse_diag_from_normal_thefts++;
+ break;
+ break;
+ case 1 : num_reverse_normal_to_diag_assignments++;
+ num_reverse_normal_from_normal_thefts++;
+ break;
+ break;
+ case 0 : num_reverse_normal_to_normal_assignments++;
+ num_reverse_normal_from_normal_thefts++;
+ break;
+ default : std::cerr << "key = " << key << std::endl;
+ throw std::runtime_error("Bug in logging, wrong key");
+ break;
+ }
+
+#endif
+}
+
+template<class R, class AO>
+typename AuctionRunnerFR<R, AO>::Real
+AuctionRunnerFR<R, AO>::get_item_bidder_cost(const size_t item_idx, const size_t bidder_idx) const
+{
+ if (wasserstein_power == 1.0) {
+ return dist_lp(bidders[bidder_idx], items[item_idx], internal_p);
+ } else {
+ return std::pow(dist_lp(bidders[bidder_idx], items[item_idx], internal_p),
+ wasserstein_power);
+ }
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::assign_to_best_bidder(IdxType item_idx)
+{
+ assert( item_idx >= 0 and item_idx < static_cast<IdxType>(num_items) );
+ assert( forward_bid_table[item_idx].first != k_invalid_index);
+
+ auto best_bidder_idx = forward_bid_table[item_idx].first;
+ auto best_bid_value = forward_bid_table[item_idx].second;
+ assign_forward(item_idx, best_bidder_idx);
+ forward_oracle.sanity_check();
+ forward_oracle.set_price(item_idx, best_bid_value, true);
+ forward_oracle.sanity_check();
+ auto new_bidder_price = -get_item_bidder_cost(item_idx, best_bidder_idx) - best_bid_value;
+ reverse_oracle.set_price(best_bidder_idx, new_bidder_price, false);
+ check_epsilon_css();
+#ifdef LOG_AUCTION
+ forward_price_change_cnt_vec.back()[item_idx]++;
+ reverse_price_change_cnt_vec.back()[best_bidder_idx]++;
+#endif
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::assign_to_best_item(IdxType bidder_idx)
+{
+ check_epsilon_css();
+ assert( bidder_idx >= 0 and bidder_idx < static_cast<IdxType>(num_bidders) );
+ assert( reverse_bid_table[bidder_idx].first != k_invalid_index);
+ auto best_item_idx = reverse_bid_table[bidder_idx].first;
+ auto best_bid_value = reverse_bid_table[bidder_idx].second;
+ // both assign_forward and assign_reverse take item index first, bidder index second!
+ assign_reverse(best_item_idx, bidder_idx);
+ reverse_oracle.sanity_check();
+ reverse_oracle.set_price(bidder_idx, best_bid_value, true);
+ reverse_oracle.sanity_check();
+ auto new_item_price = -get_item_bidder_cost(best_item_idx, bidder_idx) - best_bid_value;
+ forward_oracle.set_price(best_item_idx, new_item_price, false);
+#ifdef LOG_AUCTION
+ forward_price_change_cnt_vec.back()[best_item_idx]++;
+ reverse_price_change_cnt_vec.back()[bidder_idx]++;
+#endif
+ check_epsilon_css();
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::clear_forward_bid_table()
+{
+ auto item_iter = items_with_bids.begin();
+ while(item_iter != items_with_bids.end()) {
+ auto item_with_bid_idx = *item_iter;
+ forward_bid_table[item_with_bid_idx].first = k_invalid_index;
+ forward_bid_table[item_with_bid_idx].second = k_lowest_bid_value;
+ item_iter = items_with_bids.erase(item_iter);
+ }
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::clear_reverse_bid_table()
+{
+ auto bidder_iter = bidders_with_bids.begin();
+ while(bidder_iter != bidders_with_bids.end()) {
+ auto bidder_with_bid_idx = *bidder_iter;
+ reverse_bid_table[bidder_with_bid_idx].first = k_invalid_index;
+ reverse_bid_table[bidder_with_bid_idx].second = k_lowest_bid_value;
+ bidder_iter = bidders_with_bids.erase(bidder_iter);
+ }
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::submit_forward_bid(IdxType bidder_idx, const IdxValPairR& bid)
+{
+ IdxType best_item_idx = bid.first;
+ Real bid_value = bid.second;
+ assert( best_item_idx >= 0 );
+
+ auto value_in_bid_table = forward_bid_table[best_item_idx].second;
+ bool new_bid_wins = (value_in_bid_table < bid_value);
+ // if we have tie, lower persistence wins
+// if (value_in_bid_table == bid_value) {
+//
+// assert(forward_bid_table.at(best_item_idx).first != k_invalid_index);
+// assert(&bidders.at(forward_bid_table.at(best_item_idx).first));
+//
+// auto bidder_in_bid_table = bidders[forward_bid_table[best_item_idx].first];
+// new_bid_wins = bidders[best_item_idx].persistence_lp(internal_p) < bidder_in_bid_table.persistence_lp(internal_p);
+// }
+
+ if (new_bid_wins) {
+ forward_bid_table[best_item_idx].first = bidder_idx;
+ forward_bid_table[best_item_idx].second = bid_value;
+ }
+
+ items_with_bids.insert(best_item_idx);
+
+#ifdef LOG_AUCTION
+
+ if (unassigned_bidders.size() > parallel_threshold) {
+ num_parallel_bids++;
+ }
+ num_total_bids++;
+
+
+ if (is_bidder_diagonal(bidder_idx)) {
+ num_diag_forward_bids_submitted++;
+ } else {
+ num_normal_forward_bids_submitted++;
+ }
+#endif
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::submit_reverse_bid(IdxType item_idx, const IdxValPairR& bid)
+{
+ assert( items.at(item_idx).is_diagonal() or items.at(item_idx).is_normal() );
+ IdxType best_bidder_idx = bid.first;
+ assert( bidders.at(best_bidder_idx).is_diagonal() or bidders.at(best_bidder_idx).is_normal() );
+ Real bid_value = bid.second;
+ assert(bid_value > k_lowest_bid_value);
+ auto value_in_bid_table = reverse_bid_table[best_bidder_idx].second;
+ bool new_bid_wins = (value_in_bid_table < bid_value);
+ // if we have tie, lower persistence wins
+// if (value_in_bid_table == bid_value) {
+// assert(reverse_bid_table[best_bidder_idx].first != k_invalid_index);
+// auto bidder_in_bid_table = bidders[reverse_bid_table[best_bidder_idx].first];
+// new_bid_wins = bidders[best_bidder_idx].persistence_lp(internal_p) < bidder_in_bid_table.persistence_lp(internal_p);
+// }
+ if (new_bid_wins) {
+ reverse_bid_table[best_bidder_idx].first = item_idx;
+ reverse_bid_table[best_bidder_idx].second = bid_value;
+ }
+ bidders_with_bids.insert(best_bidder_idx);
+
+#ifdef LOG_AUCTION
+
+ if (unassigned_items.size() > parallel_threshold) {
+ num_parallel_bids++;
+ }
+ num_total_bids++;
+
+ if (is_item_diagonal(item_idx)) {
+ num_diag_reverse_bids_submitted++;
+ } else {
+ num_normal_reverse_bids_submitted++;
+ }
+#endif
+}
+
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::print_debug()
+{
+#ifdef DEBUG_FR_AUCTION
+ std::cout << "**********************" << std::endl;
+ std::cout << "Current assignment:" << std::endl;
+ for(size_t idx = 0; idx < bidders_to_items.size(); ++idx) {
+ std::cout << idx << " <--> " << bidders_to_items[idx] << std::endl;
+ }
+ std::cout << "Weights: " << std::endl;
+ //for(size_t i = 0; i < num_bidders; ++i) {
+ //for(size_t j = 0; j < num_items; ++j) {
+ //std::cout << oracle.weight_matrix[i][j] << " ";
+ //}
+ //std::cout << std::endl;
+ //}
+ std::cout << "Bidder prices: " << std::endl;
+ for(const auto price : forward_oracle.get_prices()) {
+ std::cout << price << std::endl;
+ }
+ std::cout << "**********************" << std::endl;
+#endif
+}
+
+
+template<class R, class AO>
+typename AuctionRunnerFR<R,AO>::Real
+AuctionRunnerFR<R, AO>::get_relative_error(const bool debug_output) const
+{
+ Real result;
+ Real gamma = get_gamma();
+ // cost minus n epsilon
+ Real reduced_cost = partial_cost - num_bidders * get_epsilon();
+ if ( reduced_cost < 0) {
+ result = k_max_relative_error;
+ } else {
+ Real denominator = std::pow(reduced_cost, 1.0 / wasserstein_power) - gamma;
+ if (denominator <= 0) {
+ result = k_max_relative_error;
+ } else {
+ Real numerator = 2 * gamma +
+ std::pow(partial_cost, 1.0 / wasserstein_power) -
+ std::pow(reduced_cost, 1.0 / wasserstein_power);
+
+ result = numerator / denominator;
+ }
+ }
+ return result;
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::flush_assignment()
+{
+ for(auto& b2i : bidders_to_items) {
+ b2i = k_invalid_index;
+ }
+ for(auto& i2b : items_to_bidders) {
+ i2b = k_invalid_index;
+ }
+
+ // all bidders and items become unassigned
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ unassigned_bidders.insert(bidder_idx);
+ }
+
+ // all items and items become unassigned
+ for(size_t item_idx = 0; item_idx < num_items; ++item_idx) {
+ unassigned_items.insert(item_idx);
+ }
+
+
+ //forward_oracle.adjust_prices();
+ //reverse_oracle.adjust_prices();
+
+ partial_cost = 0.0;
+ unassigned_bidders_persistence = total_bidders_persistence;
+ unassigned_items_persistence = total_items_persistence;
+
+#ifdef ORDERED_BY_PERSISTENCE
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ unassigned_bidders_by_persistence.insert(std::make_pair(bidders[bidder_idx].persistence_lp(1.0), bidder_idx));
+ }
+
+ for(size_t item_idx = 0; item_idx < num_items; ++item_idx) {
+ unassigned_items_by_persistence.insert(std::make_pair(items[item_idx].persistence_lp(1.0), item_idx));
+ }
+#endif
+
+#ifdef LOG_AUCTION
+
+ reset_phase_stat();
+
+ forward_price_change_cnt_vec.push_back(std::vector<size_t>(num_items, 0));
+ reverse_price_change_cnt_vec.push_back(std::vector<size_t>(num_bidders, 0));
+
+ // all bidders and items become unassigned
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ if (is_bidder_normal(bidder_idx)) {
+ unassigned_normal_bidders.insert(bidder_idx);
+ } else {
+ unassigned_diag_bidders.insert(bidder_idx);
+ }
+ }
+
+ never_assigned_bidders = unassigned_bidders;
+
+ for(size_t item_idx = 0; item_idx < items.size(); ++item_idx) {
+ if (is_item_normal(item_idx)) {
+ unassigned_normal_items.insert(item_idx);
+ } else {
+ unassigned_diag_items.insert(item_idx);
+ }
+ }
+
+ never_assigned_items = unassigned_items;
+#endif
+ check_epsilon_css();
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::set_epsilon(Real new_val)
+{
+ assert(new_val > 0.0);
+ epsilon = new_val;
+ forward_oracle.set_epsilon(new_val);
+ reverse_oracle.set_epsilon(new_val);
+}
+
+
+template<class R, class AO>
+bool AuctionRunnerFR<R, AO>::continue_forward(const size_t original_unassigned_bidders, const size_t min_forward_matching_increment)
+{
+// if (unassigned_threshold == 0) {
+// return not unassigned_bidders.empty() and get_relative_error(false) > delta;
+// }
+ //return unassigned_bidders.size() > unassigned_threshold and
+ //static_cast<int>(unassigned_bidders.size()) >= static_cast<int>(original_unassigned_bidders) - static_cast<int>(min_forward_matching_increment);
+ return unassigned_bidders.size() > unassigned_threshold and
+ static_cast<int>(unassigned_bidders.size()) >= static_cast<int>(original_unassigned_bidders) - static_cast<int>(min_forward_matching_increment) and
+ get_relative_error() >= delta;
+// return not unassigned_bidders.empty() and
+// static_cast<int>(unassigned_bidders.size()) >= static_cast<int>(original_unassigned_bidders) - static_cast<int>(min_forward_matching_increment) and
+// get_relative_error() >= delta;
+}
+
+
+template<class R, class AO>
+bool AuctionRunnerFR<R, AO>::continue_reverse(const size_t original_unassigned_items, const size_t min_reverse_matching_increment)
+{
+ //return unassigned_items.size() > unassigned_threshold and
+ //static_cast<int>(unassigned_items.size()) >= static_cast<int>(original_unassigned_items) - static_cast<int>(min_reverse_matching_increment);
+ return unassigned_items.size() > unassigned_threshold and
+ static_cast<int>(unassigned_items.size()) >= static_cast<int>(original_unassigned_items) - static_cast<int>(min_reverse_matching_increment) and
+ get_relative_error() >= delta;
+// return not unassigned_items.empty() and
+// static_cast<int>(unassigned_items.size()) >= static_cast<int>(original_unassigned_items) - static_cast<int>(min_reverse_matching_increment) and
+// get_relative_error() >= delta;
+}
+
+
+template<class R, class AO>
+bool AuctionRunnerFR<R, AO>::continue_phase()
+{
+ //return not unassigned_bidders.empty();
+ return unassigned_bidders.size() > unassigned_threshold and get_relative_error() >= delta;
+// return not never_assigned_bidders.empty() or
+// not never_assigned_items.empty() or
+// unassigned_bidders.size() > unassigned_threshold and get_relative_error() >= delta;
+}
+
+
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::run_auction_phase()
+{
+ num_phase++;
+ while(continue_phase()) {
+ forward_oracle.recompute_top_diag_items(true);
+ forward_oracle.sanity_check();
+ run_forward_auction_phase();
+ reverse_oracle.recompute_top_diag_items(true);
+ reverse_oracle.sanity_check();
+ run_reverse_auction_phase();
+ }
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::run_auction_phases(const int max_num_phases, const Real _initial_epsilon)
+{
+ set_epsilon(_initial_epsilon);
+ assert( forward_oracle.get_epsilon() > 0 );
+ assert( reverse_oracle.get_epsilon() > 0 );
+ for(int phase_num = 0; phase_num < max_num_phases; ++phase_num) {
+ flush_assignment();
+
+ run_auction_phase();
+ Real current_result = partial_cost;
+
+ if (get_relative_error(true) <= delta) {
+ break;
+ }
+ // decrease epsilon for the next iteration
+ decrease_epsilon();
+
+ unassigned_threshold = std::floor( static_cast<double>(unassigned_threshold) / 1.1 );
+
+ if (phase_can_be_final()) {
+ unassigned_threshold = 0;
+ }
+ }
+}
+
+template<class R, class AO>
+bool AuctionRunnerFR<R, AO>::phase_can_be_final() const
+{
+ Real estimated_error;
+ // cost minus n epsilon
+ Real reduced_cost = partial_cost - num_bidders * get_epsilon();
+ if (reduced_cost <= 0.0) {
+ return false;
+ } else {
+ Real denominator = std::pow(reduced_cost, 1.0 / wasserstein_power);
+ if (denominator <= 0) {
+ return false;
+ } else {
+ Real numerator = std::pow(partial_cost, 1.0 / wasserstein_power) -
+ std::pow(reduced_cost, 1.0 / wasserstein_power);
+
+ estimated_error = numerator / denominator;
+ return estimated_error <= delta;
+ }
+ }
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::run_auction()
+{
+ double init_eps = ( initial_epsilon > 0.0 ) ? initial_epsilon : std::min(forward_oracle.max_val_, reverse_oracle.max_val_) / 4.0 ;
+ assert(init_eps > 0.0);
+ run_auction_phases(max_num_phases, init_eps);
+ is_distance_computed = true;
+ wasserstein_cost = partial_cost;
+ if (get_relative_error() > delta) {
+#ifndef FOR_R_TDA
+ std::cerr << "Maximum iteration number exceeded, exiting. Current result is: ";
+ std::cerr << get_wasserstein_distance() << std::endl;
+#endif
+ throw std::runtime_error("Maximum iteration number exceeded");
+ }
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::add_unassigned_bidder(const size_t bidder_idx)
+{
+ const DgmPoint& bidder = bidders[bidder_idx];
+ unassigned_bidders.insert(bidder_idx);
+ unassigned_bidders_persistence += get_cost_to_diagonal(bidder);
+
+#ifdef ORDERED_BY_PERSISTENCE
+ unassigned_bidders_by_persistence.insert(std::make_pair(bidder.persistence_lp(1.0), bidder_idx));
+#endif
+
+#ifdef LOG_AUCTION
+ if (is_bidder_diagonal(bidder_idx)) {
+ unassigned_diag_bidders.insert(bidder_idx);
+ } else {
+ unassigned_normal_bidders.insert(bidder_idx);
+ }
+#endif
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::add_unassigned_item(const size_t item_idx)
+{
+ const DgmPoint& item = items[item_idx];
+ unassigned_items.insert(item_idx);
+ unassigned_items_persistence += get_cost_to_diagonal(item);
+
+#ifdef ORDERED_BY_PERSISTENCE
+ unassigned_items_by_persistence.insert(std::make_pair(item.persistence_lp(1.0), item_idx));
+#endif
+
+#ifdef LOG_AUCTION
+ if (is_item_diagonal(item_idx)) {
+ unassigned_diag_items.insert(item_idx);
+ } else {
+ unassigned_normal_items.insert(item_idx);
+ }
+#endif
+}
+
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::remove_unassigned_bidder(const size_t bidder_idx)
+{
+ unassigned_bidders_persistence -= get_cost_to_diagonal(bidders[bidder_idx]);
+
+ unassigned_bidders.erase(bidder_idx);
+ never_assigned_bidders.erase(bidder_idx);
+
+#ifdef ORDERED_BY_PERSISTENCE
+ unassigned_bidders_by_persistence.erase(std::make_pair(bidders[bidder_idx].persistence_lp(1.0), bidder_idx));
+#endif
+
+#ifdef LOG_AUCTION
+ if (is_bidder_diagonal(bidder_idx)) {
+ unassigned_diag_bidders.erase(bidder_idx);
+ } else {
+ unassigned_normal_bidders.erase(bidder_idx);
+ }
+ if (never_assigned_bidders.empty() and not all_assigned_round_found) {
+ all_assigned_round = num_rounds_non_cumulative;
+ all_assigned_round_found = true;
+ }
+#endif
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::remove_unassigned_item(const size_t item_idx)
+{
+ unassigned_items_persistence -= get_cost_to_diagonal(items[item_idx]);
+
+ never_assigned_items.erase(item_idx);
+ unassigned_items.erase(item_idx);
+
+#ifdef ORDERED_BY_PERSISTENCE
+ unassigned_items_by_persistence.erase(std::make_pair(items[item_idx].persistence_lp(1.0), item_idx));
+#endif
+
+#ifdef LOG_AUCTION
+ if (is_item_normal(item_idx)) {
+ unassigned_normal_items.erase(item_idx);
+ } else {
+ unassigned_diag_items.erase(item_idx);
+ }
+ if (never_assigned_items.empty() and not all_assigned_round_found) {
+ all_assigned_round = num_rounds_non_cumulative;
+ all_assigned_round_found = true;
+ }
+#endif
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::decrease_epsilon()
+{
+ auto eps_diff = 1.01 * get_epsilon() * (epsilon_common_ratio - 1.0 ) / epsilon_common_ratio;
+ reverse_oracle.adjust_prices( -eps_diff );
+ set_epsilon( get_epsilon() / epsilon_common_ratio );
+ cumulative_epsilon_factor *= epsilon_common_ratio;
+}
+
+
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::run_reverse_auction_phase()
+{
+ size_t original_unassigned_items = unassigned_items.size();
+// const size_t min_reverse_matching_increment = std::max( static_cast<size_t>(1), static_cast<size_t>(original_unassigned_items / 10));
+ size_t min_reverse_matching_increment = 1;
+
+ while (continue_reverse(original_unassigned_items, min_reverse_matching_increment)) {
+ num_rounds++;
+ num_rounds_non_cumulative++;
+
+ check_epsilon_css();
+#ifdef LOG_AUCTION
+ if (unassigned_items.size() >= parallel_threshold) {
+ ++num_parallelizable_reverse_rounds;
+ ++num_parallelizable_rounds;
+ }
+ num_reverse_rounds++;
+ num_reverse_rounds_non_cumulative++;
+#endif
+
+ reset_round_stat();
+ // bidding
+#ifdef ORDERED_BY_PERSISTENCE
+ std::vector<size_t> active_items;
+ active_items.reserve(batch_size);
+ for(auto iter = unassigned_items_by_persistence.begin();
+ iter != unassigned_items_by_persistence.end(); ++iter) {
+ active_items.push_back(iter->second);
+ if (active_items.size() >= batch_size) {
+ break;
+ }
+ }
+ run_reverse_bidding_step(active_items);
+#else
+ //if (not never_assigned_items.empty())
+ //run_reverse_bidding_step(never_assigned_items);
+ //else
+ //run_reverse_bidding_step(unassigned_items);
+ run_reverse_bidding_step(unassigned_items);
+#endif
+
+ // assignment phase
+ for(auto bidder_idx : bidders_with_bids ) {
+ assign_to_best_item(bidder_idx);
+ }
+
+ check_epsilon_css();
+ }
+}
+
+template<class R, class AO>
+template<class Range>
+void AuctionRunnerFR<R, AO>::run_forward_bidding_step(const Range& active_bidders)
+{
+ clear_forward_bid_table();
+ for(const auto bidder_idx : active_bidders) {
+ submit_forward_bid(bidder_idx, forward_oracle.get_optimal_bid(bidder_idx));
+ if (++num_forward_bids_submitted >= max_bids_per_round) {
+ break;
+ }
+ }
+}
+
+template<class R, class AO>
+template<class Range>
+void AuctionRunnerFR<R, AO>::run_reverse_bidding_step(const Range& active_items)
+{
+ clear_reverse_bid_table();
+
+ assert(bidders_with_bids.empty());
+ assert(std::all_of(reverse_bid_table.begin(), reverse_bid_table.end(),
+ [ki = k_invalid_index, kl = k_lowest_bid_value](const IdxValPairR& b) { return static_cast<size_t>(b.first) == ki and b.second == kl; }));
+
+ for(const auto item_idx : active_items) {
+ submit_reverse_bid(item_idx, reverse_oracle.get_optimal_bid(item_idx));
+ if (++num_reverse_bids_submitted >= max_bids_per_round) {
+ break;
+ }
+ }
+}
+
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::run_forward_auction_phase()
+{
+ const size_t original_unassigned_bidders = unassigned_bidders.size();
+// const size_t min_forward_matching_increment = std::max( static_cast<size_t>(1), static_cast<size_t>(original_unassigned_bidders / 10));
+ const size_t min_forward_matching_increment = 1;
+ while (continue_forward(original_unassigned_bidders, min_forward_matching_increment)) {
+ check_epsilon_css();
+ num_rounds++;
+#ifdef LOG_AUCTION
+ if (unassigned_bidders.size() >= parallel_threshold) {
+ ++num_parallelizable_forward_rounds;
+ ++num_parallelizable_rounds;
+ }
+ num_forward_rounds++;
+ num_forward_rounds_non_cumulative++;
+#endif
+
+ reset_round_stat();
+ // bidding step
+#ifdef ORDERED_BY_PERSISTENCE
+ std::vector<size_t> active_bidders;
+ active_bidders.reserve(batch_size);
+ for(auto iter = unassigned_bidders_by_persistence.begin();
+ iter != unassigned_bidders_by_persistence.end(); ++iter) {
+ active_bidders.push_back(iter->second);
+ if (active_bidders.size() >= batch_size) {
+ break;
+ }
+ }
+ run_forward_bidding_step(active_bidders);
+#else
+
+ //if (not never_assigned_bidders.empty())
+ //run_forward_bidding_step(never_assigned_bidders);
+ //else
+ //run_forward_bidding_step(unassigned_bidders);
+ run_forward_bidding_step(unassigned_bidders);
+#endif
+
+ // assignment step
+ for(auto item_idx : items_with_bids ) {
+ assign_to_best_bidder(item_idx);
+ }
+
+ check_epsilon_css();
+
+#ifdef LOG_AUCTION
+ forward_plot_logger->info("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14} {15} {16} {17} {18} {19} {20} {21} {22}",
+ num_phase,
+ num_rounds,
+ num_forward_rounds,
+ unassigned_bidders.size(),
+ get_gamma(),
+ partial_cost,
+ forward_oracle.get_epsilon(),
+ num_normal_forward_bids_submitted,
+ num_diag_forward_bids_submitted,
+ num_forward_diag_to_diag_assignments,
+ num_forward_diag_to_normal_assignments,
+ num_forward_normal_to_diag_assignments,
+ num_forward_normal_to_normal_assignments,
+ num_forward_diag_from_diag_thefts,
+ num_forward_diag_from_normal_thefts,
+ num_forward_normal_from_diag_thefts,
+ num_forward_normal_from_normal_thefts,
+ unassigned_normal_bidders.size(),
+ unassigned_diag_bidders.size(),
+ unassigned_normal_items.size(),
+ unassigned_diag_items.size(),
+ forward_oracle.get_heap_top_size(),
+ get_relative_error(false)
+ );
+#endif
+ } ;
+
+}
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::assign_diag_to_diag()
+{
+ size_t n_diag_to_diag = std::min(num_diag_bidders, num_diag_items);
+ if (n_diag_to_diag < 2)
+ return;
+ for(size_t i = 0; i < n_diag_to_diag; ++i) {
+ }
+}
+
+template<class R, class AO>
+typename AuctionRunnerFR<R, AO>::Real
+AuctionRunnerFR<R, AO>::get_wasserstein_distance()
+{
+ assert(is_distance_computed);
+ return std::pow(wasserstein_cost, 1.0 / wasserstein_power);
+}
+
+template<class R, class AO>
+typename AuctionRunnerFR<R, AO>::Real
+AuctionRunnerFR<R, AO>::get_wasserstein_cost()
+{
+ assert(is_distance_computed);
+ return wasserstein_cost;
+}
+
+
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::sanity_check()
+{
+#ifdef DEBUG_FR_AUCTION
+ assert(partial_cost >= 0);
+
+
+ assert(num_diag_items == num_normal_bidders);
+ assert(num_diag_bidders == num_normal_items);
+ assert(num_diag_bidders + num_normal_bidders == num_bidders);
+ assert(num_diag_items + num_normal_items == num_items);
+ assert(num_items == num_bidders);
+
+
+ for(size_t b = 0; b < num_bidders; ++b) {
+ assert( is_bidder_diagonal(b) == bidders.at(b).is_diagonal() );
+ assert( is_bidder_normal(b) == bidders.at(b).is_normal() );
+ }
+
+ for(size_t i = 0; i < num_items; ++i) {
+ assert( is_item_diagonal(i) == items.at(i).is_diagonal() );
+ assert( is_item_normal(i) == items.at(i).is_normal() );
+ }
+
+ // check matching consistency
+ assert(bidders_to_items.size() == num_bidders);
+ assert(items_to_bidders.size() == num_bidders);
+
+ assert(std::count(bidders_to_items.begin(), bidders_to_items.end(), k_invalid_index) == std::count(items_to_bidders.begin(), items_to_bidders.end(), k_invalid_index));
+
+ Real true_partial_cost = 0.0;
+
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ if (bidders_to_items[bidder_idx] != k_invalid_index) {
+ assert(items_to_bidders.at(bidders_to_items[bidder_idx]) == static_cast<int>(bidder_idx));
+ true_partial_cost += get_item_bidder_cost(bidders_to_items[bidder_idx], bidder_idx);
+ }
+ }
+
+ assert(fabs(partial_cost - true_partial_cost) < 0.00001);
+
+ for(size_t item_idx = 0; item_idx < num_items; ++item_idx) {
+ if (items_to_bidders[item_idx] != k_invalid_index) {
+ assert(bidders_to_items.at(items_to_bidders[item_idx]) == static_cast<int>(item_idx));
+ }
+ }
+
+#ifdef ORDERED_BY_PERSISTENCE
+ assert(unassigned_bidders.size() == unassigned_bidders_by_persistence.size());
+ assert(unassigned_items.size() == unassigned_items_by_persistence.size());
+
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ if (bidders_to_items[bidder_idx] == k_invalid_index) {
+ assert(unassigned_bidders.count(bidder_idx) == 1);
+ assert(unassigned_bidders_by_persistence.count(std::make_pair(bidders[bidder_idx].persistence_lp(1.0), bidder_idx)) == 1);
+ } else {
+ assert(unassigned_bidders.count(bidder_idx) == 0);
+ assert(unassigned_bidders_by_persistence.count(std::make_pair(bidders[bidder_idx].persistence_lp(1.0), bidder_idx)) == 0);
+ }
+ }
+
+ for(size_t item_idx = 0; item_idx < num_items; ++item_idx) {
+ if (items_to_bidders[item_idx] == k_invalid_index) {
+ assert(unassigned_items.count(item_idx) == 1);
+ assert(unassigned_items_by_persistence.count(std::make_pair(items[item_idx].persistence_lp(1.0), item_idx)) == 1);
+ } else {
+ assert(unassigned_items.count(item_idx) == 0);
+ assert(unassigned_items_by_persistence.count(std::make_pair(items[item_idx].persistence_lp(1.0), item_idx)) == 0);
+ }
+ }
+#endif
+
+
+#endif
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::check_epsilon_css()
+{
+#ifdef DEBUG_FR_AUCTION
+ sanity_check();
+
+ std::vector<double> b_prices = reverse_oracle.get_prices();
+ std::vector<double> i_prices = forward_oracle.get_prices();
+ double eps = forward_oracle.get_epsilon();
+
+ for(size_t b = 0; b < num_bidders; ++b) {
+ for(size_t i = 0; i < num_items; ++i) {
+ if(((is_bidder_normal(b) and is_item_diagonal(i)) or (is_bidder_diagonal(b) and is_item_normal(i))) and b != i)
+ continue;
+ assert(b_prices[b] + i_prices[i] + eps >= -get_item_bidder_cost(i, b) - 0.000001);
+ }
+ }
+
+ for(size_t b = 0; b < num_bidders; ++b) {
+ auto i = bidders_to_items[b];
+ if (i != k_invalid_index) {
+ assert( fabs(b_prices[b] + i_prices[i] + get_item_bidder_cost(i, b)) < 0.000001 );
+ }
+ }
+#endif
+}
+
+template<class R, class AO>
+void AuctionRunnerFR<R, AO>::print_matching()
+{
+#ifdef DEBUG_FR_AUCTION
+ sanity_check();
+ for(size_t bidder_idx = 0; bidder_idx < bidders_to_items.size(); ++bidder_idx) {
+ if (bidders_to_items[bidder_idx] >= 0) {
+ auto pA = bidders[bidder_idx];
+ auto pB = items[bidders_to_items[bidder_idx]];
+ std::cout << pA << " <-> " << pB << "+" << pow(dist_lp(pA, pB, internal_p), wasserstein_power) << std::endl;
+ } else {
+ assert(false);
+ }
+ }
+#endif
+}
+
+} // ws
+} // hera
+
+#endif
diff --git a/wasserstein/include/auction_runner_gs.h b/wasserstein/include/auction_runner_gs.h
new file mode 100644
index 0000000..8ad95c2
--- /dev/null
+++ b/wasserstein/include/auction_runner_gs.h
@@ -0,0 +1,122 @@
+/*
+
+Copyright (c) 2016, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_RUNNER_GS_H
+#define AUCTION_RUNNER_GS_H
+
+#include <memory>
+#include <unordered_set>
+
+#include "auction_oracle.h"
+
+namespace hera {
+namespace ws {
+
+template<class RealType_ = double, class AuctionOracle_ = AuctionOracleKDTreeRestricted<RealType_>, class PointContainer_ = std::vector<DiagramPoint<RealType_>> > // alternatively: AuctionOracleLazyHeap --- TODO
+class AuctionRunnerGS {
+public:
+ using Real = RealType_;
+ using AuctionOracle = AuctionOracle_;
+ using DgmPoint = typename AuctionOracle::DiagramPointR;
+ using IdxValPairR = IdxValPair<Real>;
+ using PointContainer = PointContainer_;
+
+
+ AuctionRunnerGS(const PointContainer& A,
+ const PointContainer& B,
+ const AuctionParams<Real>& params,
+ const std::string& _log_filename_prefix = "");
+
+ void set_epsilon(Real new_val) { assert(epsilon > 0.0); epsilon = new_val; };
+ Real get_epsilon() const { return oracle.get_epsilon(); }
+ Real get_wasserstein_cost();
+ Real get_wasserstein_distance();
+ Real get_relative_error() const { return relative_error; };
+ void enable_logging(const char* log_filename, const size_t _max_unassigned_to_log);
+//private:
+ // private data
+ PointContainer bidders, items;
+ const size_t num_bidders;
+ const size_t num_items;
+ std::vector<IdxType> items_to_bidders;
+ std::vector<IdxType> bidders_to_items;
+ Real wasserstein_power;
+ Real epsilon;
+ Real delta;
+ Real internal_p;
+ Real initial_epsilon;
+ Real epsilon_common_ratio; // next epsilon = current epsilon / epsilon_common_ratio
+ const int max_num_phases; // maximal number of iterations of epsilon-scaling
+ bool tolerate_max_iter_exceeded;
+ Real weight_adj_const;
+ Real wasserstein_cost;
+ Real relative_error;
+ int dimension;
+ // to get the 2 best items
+ AuctionOracle oracle;
+ std::unordered_set<size_t> unassigned_bidders;
+ // private methods
+ void assign_item_to_bidder(const IdxType bidder_idx, const IdxType items_idx);
+ void run_auction();
+ void run_auction_phases(const int max_num_phases, const Real _initial_epsilon);
+ void run_auction_phase();
+ void flush_assignment();
+ // return 0, if item_idx is invalid
+ Real get_item_bidder_cost(const size_t item_idx, const size_t bidder_idx, const bool tolerate_invalid_idx = false) const;
+
+ // for debug only
+ void sanity_check();
+ void print_debug();
+ int count_unhappy();
+ void print_matching();
+ Real getDistanceToQthPowerInternal();
+ int num_phase { 0 };
+ int num_rounds { 0 };
+ bool is_distance_computed {false};
+#ifdef LOG_AUCTION
+ bool log_auction { false };
+ std::shared_ptr<spdlog::logger> console_logger;
+ std::shared_ptr<spdlog::logger> plot_logger;
+ std::unordered_set<size_t> unassigned_items;
+ size_t max_unassigned_to_log { 0 };
+ const char* logger_name = "auction_detailed_logger"; // the name in spdlog registry; filename is provided as parameter in enable_logging
+ const Real total_items_persistence;
+ const Real total_bidders_persistence;
+ Real partial_cost;
+ Real unassigned_bidders_persistence;
+ Real unassigned_items_persistence;
+#endif
+};
+
+} // ws
+} // hera
+
+
+#include "auction_runner_gs.hpp"
+
+#endif
diff --git a/wasserstein/include/auction_runner_gs.hpp b/wasserstein/include/auction_runner_gs.hpp
new file mode 100644
index 0000000..4ef94db
--- /dev/null
+++ b/wasserstein/include/auction_runner_gs.hpp
@@ -0,0 +1,494 @@
+/*
+
+Copyright (c) 2016, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+
+#include <assert.h>
+#include <stdexcept>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <chrono>
+#include <numeric>
+
+#include "def_debug_ws.h"
+
+#define PRINT_DETAILED_TIMING
+
+#ifdef FOR_R_TDA
+#include "Rcpp.h"
+#undef DEBUG_AUCTION
+#endif
+
+
+namespace hera {
+namespace ws {
+
+// *****************************
+// AuctionRunnerGS
+// *****************************
+
+template<class R, class AO, class PC>
+AuctionRunnerGS<R, AO, PC>::AuctionRunnerGS(const PC& A,
+ const PC& B,
+ const AuctionParams<Real>& params,
+ const std::string& _log_filename_prefix) :
+ bidders(A),
+ items(B),
+ num_bidders(A.size()),
+ num_items(B.size()),
+ items_to_bidders(B.size(), k_invalid_index),
+ bidders_to_items(A.size(), k_invalid_index),
+ wasserstein_power(params.wasserstein_power),
+ delta(params.delta),
+ internal_p(params.internal_p),
+ initial_epsilon(params.initial_epsilon),
+ epsilon_common_ratio(params.epsilon_common_ratio == 0.0 ? 5.0 : params.epsilon_common_ratio),
+ max_num_phases(params.max_num_phases),
+ tolerate_max_iter_exceeded(params.tolerate_max_iter_exceeded),
+ dimension(params.dim),
+ oracle(bidders, items, params)
+#ifdef LOG_AUCTION
+ , total_items_persistence(std::accumulate(items.begin(),
+ items.end(),
+ R(0.0),
+ [params](const Real& ps, const DgmPoint& item)
+ { return ps + std::pow(item.persistence_lp(params.internal_p), params.wasserstein_power); }
+ ))
+
+ , total_bidders_persistence(std::accumulate(bidders.begin(),
+ bidders.end(),
+ R(0.0),
+ [params](const Real& ps, const DgmPoint& bidder)
+ { return ps + std::pow(bidder.persistence_lp(params.internal_p), params.wasserstein_power); }
+ ))
+ , partial_cost(0.0)
+ , unassigned_bidders_persistence(0.0)
+ , unassigned_items_persistence(0.0)
+#endif
+
+{
+ assert(initial_epsilon >= 0.0 );
+ assert(epsilon_common_ratio >= 0.0 );
+ assert(A.size() == B.size());
+#ifdef LOG_AUCTION
+
+ unassigned_items_persistence = total_items_persistence;
+ unassigned_bidders_persistence = total_bidders_persistence;
+
+ console_logger = spdlog::get("console");
+ if (not console_logger) {
+ console_logger = spdlog::stdout_logger_st("console");
+ }
+ console_logger->set_pattern("[%H:%M:%S.%e] %v");
+ console_logger->debug("Gauss-Seidel, num_bidders = {0}", num_bidders);
+
+ plot_logger = spdlog::get("plot_logger");
+ if (not plot_logger) {
+ plot_logger = spdlog::basic_logger_st("plot_logger", "plot_logger.txt");
+ plot_logger->info("New plot starts here");
+ plot_logger->set_pattern("%v");
+ }
+#endif
+
+}
+
+#ifdef LOG_AUCTION
+template<class R, class AO, class PC>
+void AuctionRunnerGS<R, AO, PC>::enable_logging(const char* log_filename, const size_t _max_unassigned_to_log)
+{
+ log_auction = true;
+ max_unassigned_to_log = _max_unassigned_to_log;
+
+ auto log = spdlog::basic_logger_st(logger_name, log_filename);
+ log->set_pattern("%v");
+}
+#endif
+
+template<class R, class AO, class PC>
+void AuctionRunnerGS<R, AO, PC>::assign_item_to_bidder(IdxType item_idx, IdxType bidder_idx)
+{
+ num_rounds++;
+ sanity_check();
+ // only unassigned bidders should submit bids and get items
+ assert(bidders_to_items[bidder_idx] == k_invalid_index);
+ IdxType old_item_owner = items_to_bidders[item_idx];
+
+ // set new owner
+ bidders_to_items[bidder_idx] = item_idx;
+ items_to_bidders[item_idx] = bidder_idx;
+ // remove bidder from the list of unassigned bidders
+ unassigned_bidders.erase(bidder_idx);
+
+ // old owner becomes unassigned
+ if (old_item_owner != k_invalid_index) {
+ bidders_to_items[old_item_owner] = k_invalid_index;
+ unassigned_bidders.insert(old_item_owner);
+ }
+
+
+#ifdef LOG_AUCTION
+
+ partial_cost += get_item_bidder_cost(item_idx, bidder_idx, true);
+ partial_cost -= get_item_bidder_cost(item_idx, old_item_owner, true);
+
+ unassigned_items.erase(item_idx);
+
+ unassigned_bidders_persistence -= std::pow(bidders[bidder_idx].persistence_lp(internal_p), wasserstein_power);
+
+ if (old_item_owner != k_invalid_index) {
+ // item has been assigned to some other bidder,
+ // and he became unassigned
+ unassigned_bidders_persistence += std::pow(bidders[old_item_owner].persistence_lp(internal_p), wasserstein_power);
+ } else {
+ // item was unassigned before
+ unassigned_items_persistence -= std::pow(items[item_idx].persistence_lp(internal_p), wasserstein_power);
+ }
+
+ if (log_auction)
+ plot_logger->info("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}",
+ num_phase,
+ num_rounds,
+ unassigned_bidders.size(),
+ unassigned_items_persistence,
+ unassigned_bidders_persistence,
+ unassigned_items_persistence + unassigned_bidders_persistence,
+ partial_cost,
+ total_bidders_persistence,
+ total_items_persistence,
+ oracle.get_epsilon()
+ );
+
+
+ if (log_auction and unassigned_bidders.size() <= max_unassigned_to_log) {
+ auto logger = spdlog::get(logger_name);
+ if (logger) {
+ auto item = items[item_idx];
+ auto bidder = bidders[bidder_idx];
+ logger->info("{0} # ({1}, {2}) # ({3}, {4}) # {5} # {6} # {7}",
+ num_rounds,
+ item.getRealX(),
+ item.getRealY(),
+ bidder.getRealX(),
+ bidder.getRealY(),
+ format_point_set_to_log(unassigned_bidders, bidders),
+ format_point_set_to_log(unassigned_items, items),
+ oracle.get_epsilon());
+ }
+ }
+#endif
+}
+
+
+template<class R, class AO, class PC>
+void AuctionRunnerGS<R, AO, PC>::flush_assignment()
+{
+ for(auto& b2i : bidders_to_items) {
+ b2i = k_invalid_index;
+ }
+ for(auto& i2b : items_to_bidders) {
+ i2b = k_invalid_index;
+ }
+ // we must flush assignment only after we got perfect matching
+ assert(unassigned_bidders.empty());
+ // all bidders become unassigned
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ unassigned_bidders.insert(bidder_idx);
+ }
+ assert(unassigned_bidders.size() == bidders.size());
+
+#ifdef LOG_AUCTION
+ partial_cost = 0.0;
+ unassigned_bidders_persistence = total_bidders_persistence;
+ unassigned_items_persistence = total_items_persistence;
+
+ for(size_t item_idx = 0; item_idx < items.size(); ++item_idx) {
+ unassigned_items.insert(item_idx);
+ }
+#endif
+
+ oracle.adjust_prices();
+}
+
+
+template<class R, class AO, class PC>
+void AuctionRunnerGS<R, AO, PC>::run_auction_phases(const int max_num_phases, const Real _initial_epsilon)
+{
+ relative_error = std::numeric_limits<Real>::max();
+ // choose some initial epsilon
+ oracle.set_epsilon(_initial_epsilon);
+ assert( oracle.get_epsilon() > 0 );
+ for(int phase_num = 0; phase_num < max_num_phases; ++phase_num) {
+ flush_assignment();
+ run_auction_phase();
+ Real current_result = getDistanceToQthPowerInternal();
+// Real current_result_1 = 0.0;
+// for(size_t i = 0; i < num_bidders; ++i) {
+// current_result_1 += oracle.traits.distance(bidders[i], items[bidders_to_items[i]]);
+// }
+// current_result = current_result_1;
+// assert(fabs(current_result - current_result_1) < 0.001);
+ Real denominator = current_result - num_bidders * oracle.get_epsilon();
+ current_result = pow(current_result, 1.0 / wasserstein_power);
+#ifdef LOG_AUCTION
+ console_logger->info("Phase {0} done, num_rounds (cumulative) = {1}, current_result = {2}, epsilon = {3}",
+ phase_num, format_int(num_rounds), current_result,
+ oracle.get_epsilon());
+#endif
+ if ( denominator <= 0 ) {
+#ifdef LOG_AUCTION
+ console_logger->info("Epsilon is too large");
+#endif
+ } else {
+ denominator = pow(denominator, 1.0 / wasserstein_power);
+ Real numerator = current_result - denominator;
+ relative_error = numerator / denominator;
+ // spdlog::get("console")->info("relative error = {} / {} = {}, result = {}", numerator, denominator, relative_error, current_result);
+#ifdef LOG_AUCTION
+ console_logger->info("error = {0} / {1} = {2}",
+ numerator, denominator, relative_error);
+#endif
+ if (relative_error <= delta) {
+ break;
+ }
+ }
+ // decrease epsilon for the next iteration
+ oracle.set_epsilon( oracle.get_epsilon() / epsilon_common_ratio );
+ }
+}
+
+
+template<class R, class AO, class PC>
+void AuctionRunnerGS<R, AO, PC>::run_auction()
+{
+
+ if (num_bidders == 1) {
+ assign_item_to_bidder(0, 0);
+ wasserstein_cost = get_item_bidder_cost(0,0);
+ is_distance_computed = true;
+ return;
+ }
+
+ double init_eps = ( initial_epsilon > 0.0 ) ? initial_epsilon : oracle.max_val_ / 4.0 ;
+ run_auction_phases(max_num_phases, init_eps);
+ is_distance_computed = true;
+ if (relative_error > delta and not tolerate_max_iter_exceeded) {
+#ifndef FOR_R_TDA
+ std::cerr << "Maximum iteration number exceeded, exiting. Current result is: ";
+ std::cerr << pow(wasserstein_cost, 1.0/wasserstein_power) << std::endl;
+#endif
+ throw std::runtime_error("Maximum iteration number exceeded");
+ }
+}
+
+
+template<class R, class AO, class PC>
+void AuctionRunnerGS<R, AO, PC>::run_auction_phase()
+{
+ num_phase++;
+ //std::cout << "Entered run_auction_phase" << std::endl;
+ do {
+ size_t bidder_idx = *unassigned_bidders.begin();
+ auto optimal_bid = oracle.get_optimal_bid(bidder_idx);
+ auto optimal_item_idx = optimal_bid.first;
+ auto bid_value = optimal_bid.second;
+ assign_item_to_bidder(optimal_bid.first, bidder_idx);
+ oracle.set_price(optimal_item_idx, bid_value);
+ //print_debug();
+#ifdef FOR_R_TDA
+ if ( num_rounds % 10000 == 0 ) {
+ Rcpp::check_user_interrupt();
+ }
+#endif
+ } while (not unassigned_bidders.empty());
+ //std::cout << "run_auction_phase finished" << std::endl;
+
+#ifdef DEBUG_AUCTION
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ if ( bidders_to_items[bidder_idx] < 0 or bidders_to_items[bidder_idx] >= (IdxType)num_bidders) {
+ std::cerr << "After auction terminated bidder " << bidder_idx;
+ std::cerr << " has no items assigned" << std::endl;
+ throw std::runtime_error("Auction did not give a perfect matching");
+ }
+ }
+#endif
+
+}
+
+template<class R, class AO, class PC>
+R AuctionRunnerGS<R, AO, PC>::get_item_bidder_cost(const size_t item_idx, const size_t bidder_idx, const bool tolerate_invalid_idx) const
+{
+ if (item_idx != k_invalid_index and bidder_idx != k_invalid_index) {
+ return std::pow(dist_lp(bidders[bidder_idx], items[item_idx], internal_p, dimension), wasserstein_power);
+ } else {
+ if (tolerate_invalid_idx)
+ return R(0.0);
+ else
+ throw std::runtime_error("Invalid idx in get_item_bidder_cost, item_idx = " + std::to_string(item_idx) + ", bidder_idx = " + std::to_string(bidder_idx));
+ }
+}
+
+template<class R, class AO, class PC>
+R AuctionRunnerGS<R, AO, PC>::getDistanceToQthPowerInternal()
+{
+ sanity_check();
+ Real result = 0.0;
+ //std::cout << "-------------------------------------------------------------------------\n";
+ for(size_t bIdx = 0; bIdx < num_bidders; ++bIdx) {
+ result += get_item_bidder_cost(bidders_to_items[bIdx], bIdx);
+ }
+ //std::cout << "-------------------------------------------------------------------------\n";
+ wasserstein_cost = result;
+ return result;
+}
+
+template<class R, class AO, class PC>
+R AuctionRunnerGS<R, AO, PC>::get_wasserstein_distance()
+{
+ assert(is_distance_computed);
+ return pow(get_wasserstein_cost(), 1.0/wasserstein_power);
+}
+
+template<class R, class AO, class PC>
+R AuctionRunnerGS<R, AO, PC>::get_wasserstein_cost()
+{
+ assert(is_distance_computed);
+ return wasserstein_cost;
+}
+
+
+
+// Debug routines
+
+template<class R, class AO, class PC>
+void AuctionRunnerGS<R, AO, PC>::print_debug()
+{
+#ifdef DEBUG_AUCTION
+ sanity_check();
+ std::cout << "**********************" << std::endl;
+ std::cout << "Current assignment:" << std::endl;
+ for(size_t idx = 0; idx < bidders_to_items.size(); ++idx) {
+ std::cout << idx << " <--> " << bidders_to_items[idx] << std::endl;
+ }
+ std::cout << "Weights: " << std::endl;
+ //for(size_t i = 0; i < num_bidders; ++i) {
+ //for(size_t j = 0; j < num_items; ++j) {
+ //std::cout << oracle.weight_matrix[i][j] << " ";
+ //}
+ //std::cout << std::endl;
+ //}
+ std::cout << "Prices: " << std::endl;
+ for(const auto price : oracle.get_prices()) {
+ std::cout << price << std::endl;
+ }
+ std::cout << "**********************" << std::endl;
+#endif
+}
+
+
+template<class R, class AO, class PC>
+void AuctionRunnerGS<R, AO, PC>::sanity_check()
+{
+#ifdef DEBUG_AUCTION
+ if (bidders_to_items.size() != num_bidders) {
+ std::cerr << "Wrong size of bidders_to_items, must be " << num_bidders << ", is " << bidders_to_items.size() << std::endl;
+ throw std::runtime_error("Wrong size of bidders_to_items");
+ }
+
+ if (items_to_bidders.size() != num_bidders) {
+ std::cerr << "Wrong size of items_to_bidders, must be " << num_bidders << ", is " << items_to_bidders.size() << std::endl;
+ throw std::runtime_error("Wrong size of items_to_bidders");
+ }
+
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ assert( bidders_to_items[bidder_idx] == k_invalid_index or ( bidders_to_items[bidder_idx] < (IdxType)num_items and bidders_to_items[bidder_idx] >= 0));
+
+ if ( bidders_to_items[bidder_idx] != k_invalid_index) {
+
+ if ( std::count(bidders_to_items.begin(),
+ bidders_to_items.end(),
+ bidders_to_items[bidder_idx]) > 1 ) {
+ std::cerr << "Item " << bidders_to_items[bidder_idx];
+ std::cerr << " appears in bidders_to_items more than once" << std::endl;
+ throw std::runtime_error("Duplicate in bidders_to_items");
+ }
+
+ if (items_to_bidders.at(bidders_to_items[bidder_idx]) != static_cast<int>(bidder_idx)) {
+ std::cerr << "Inconsitency: bidder_idx = " << bidder_idx;
+ std::cerr << ", item_idx in bidders_to_items = ";
+ std::cerr << bidders_to_items[bidder_idx];
+ std::cerr << ", bidder_idx in items_to_bidders = ";
+ std::cerr << items_to_bidders[bidders_to_items[bidder_idx]] << std::endl;
+ throw std::runtime_error("inconsistent mapping");
+ }
+ }
+ }
+
+ for(IdxType item_idx = 0; item_idx < static_cast<IdxType>(num_bidders); ++item_idx) {
+ assert( items_to_bidders[item_idx] == k_invalid_index or ( items_to_bidders[item_idx] < static_cast<IdxType>(num_items) and items_to_bidders[item_idx] >= 0));
+ if ( items_to_bidders.at(item_idx) != k_invalid_index) {
+
+ // check for uniqueness
+ if ( std::count(items_to_bidders.begin(),
+ items_to_bidders.end(),
+ items_to_bidders[item_idx]) > 1 ) {
+ std::cerr << "Bidder " << items_to_bidders[item_idx];
+ std::cerr << " appears in items_to_bidders more than once" << std::endl;
+ throw std::runtime_error("Duplicate in items_to_bidders");
+ }
+ // check for consistency
+ if (bidders_to_items.at(items_to_bidders.at(item_idx)) != static_cast<int>(item_idx)) {
+ std::cerr << "Inconsitency: item_idx = " << item_idx;
+ std::cerr << ", bidder_idx in items_to_bidders = ";
+ std::cerr << items_to_bidders[item_idx];
+ std::cerr << ", item_idx in bidders_to_items= ";
+ std::cerr << bidders_to_items[items_to_bidders[item_idx]] << std::endl;
+ throw std::runtime_error("inconsistent mapping");
+ }
+ }
+ }
+#endif
+}
+
+template<class R, class AO, class PC>
+void AuctionRunnerGS<R, AO, PC>::print_matching()
+{
+#ifdef DEBUG_AUCTION
+ sanity_check();
+ for(size_t bIdx = 0; bIdx < bidders_to_items.size(); ++bIdx) {
+ if (bidders_to_items[bIdx] != k_invalid_index) {
+ auto pA = bidders[bIdx];
+ auto pB = items[bidders_to_items[bIdx]];
+ std::cout << pA << " <-> " << pB << "+" << pow(dist_lp(pA, pB, internal_p, dimension), wasserstein_power) << std::endl;
+ } else {
+ assert(false);
+ }
+ }
+#endif
+}
+
+} // ws
+} // hera
diff --git a/wasserstein/include/auction_runner_gs_single_diag.h b/wasserstein/include/auction_runner_gs_single_diag.h
new file mode 100644
index 0000000..f32fbbc
--- /dev/null
+++ b/wasserstein/include/auction_runner_gs_single_diag.h
@@ -0,0 +1,149 @@
+/*
+
+Copyright (c) 2016, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef AUCTION_RUNNER_GS_SINGLE_DIAG_H
+#define AUCTION_RUNNER_GS_SINGLE_DIAG_H
+
+#include <unordered_set>
+#include <unordered_map>
+
+#include "auction_oracle.h"
+
+namespace hera {
+namespace ws {
+
+// the two parameters that you can tweak in auction algorithm are:
+// 1. epsilon_common_ratio
+// 2. max_iter_num
+
+template<class RealType_, class AuctionOracle_ = AuctionOracleKDTreeSingleDiag<RealType_> > // alternatively: AuctionOracleLazyHeap --- TODO
+class AuctionRunnerGaussSeidelSingleDiag {
+public:
+ using RealType = RealType_;
+ using Real = RealType_;
+ using AuctionOracle = AuctionOracle_;
+ using DgmPoint = DiagramPoint<Real>;
+ using DgmPointVec = std::vector<DgmPoint>;
+ using DiagonalBidR = DiagonalBid<Real>;
+
+
+
+ AuctionRunnerGaussSeidelSingleDiag(const DgmPointVec& A,
+ const DgmPointVec& B,
+ const Real q,
+ const Real _delta,
+ const Real _internal_p,
+ const Real _initial_epsilon,
+ const Real _eps_factor,
+ const int _max_iter_num = std::numeric_limits<int>::max());
+
+ void set_epsilon(Real new_val) { oracle->set_epsilon(new_val); };
+ Real get_epsilon() const { return oracle->get_epsilon(); }
+ Real get_wasserstein_cost();
+ Real get_wasserstein_distance();
+ Real get_relative_error() const { return relative_error; };
+ void enable_logging(const char* log_filename, const size_t _max_unassigned_to_log);
+//private:
+ // private data
+ DgmPointVec bidders, items;
+ const size_t num_bidders;
+ const size_t num_items;
+ size_t num_normal_bidders;
+ size_t num_diag_bidders;
+ size_t num_normal_items;
+ size_t num_diag_items;
+ std::vector<IdxType> items_to_bidders;
+ std::vector<IdxType> bidders_to_items;
+ const Real wasserstein_power;
+ const Real delta;
+ const Real internal_p;
+ const Real initial_epsilon;
+ Real epsilon_common_ratio; // next epsilon = current epsilon / epsilon_common_ratio
+ const int max_iter_num; // maximal number of iterations of epsilon-scaling
+ Real weight_adj_const;
+ Real wasserstein_cost;
+ Real relative_error;
+ // to get the 2 best items we use oracle
+ std::unique_ptr<AuctionOracle> oracle;
+ // unassigned guys
+ std::unordered_set<size_t> unassigned_normal_bidders;
+ std::unordered_set<size_t> unassigned_diag_bidders;
+ // private methods
+ //
+ void process_diagonal_bid(const DiagonalBidR& bid);
+
+ void assign_item_to_bidder(const IdxType item_idx,
+ const IdxType bidder_idx,
+ const IdxType old_owner_idx,
+ const bool item_is_diagonal,
+ const bool bidder_is_diagonal,
+ const bool call_set_prices = false,
+ const Real new_price = std::numeric_limits<Real>::max());
+
+ void run_auction();
+ void run_auction_phases(const int max_num_phases, const Real _initial_epsilon);
+ void run_auction_phase();
+ void flush_assignment();
+ // return 0, if item_idx is invalid
+ Real get_item_bidder_cost(const size_t item_idx, const size_t bidder_idx, const bool tolerate_invalid_idx = false) const;
+
+ bool is_bidder_diagonal(const size_t bidder_idx) const;
+ bool is_bidder_normal(const size_t bidder_idx) const;
+ bool is_item_diagonal(const size_t item_idx) const;
+ bool is_item_normal(const size_t item_idx) const;
+
+ OwnerType get_owner_type(size_t bidder_idx) const;
+
+ // for debug only
+ void sanity_check();
+ void print_debug();
+ int count_unhappy();
+ void print_matching();
+ Real getDistanceToQthPowerInternal();
+ int num_phase { 0 };
+ int num_rounds { 0 };
+#ifdef LOG_AUCTION
+ bool log_auction { false };
+ std::unordered_set<size_t> unassigned_items;
+ size_t max_unassigned_to_log { 0 };
+ const char* logger_name = "auction_detailed_logger"; // the name in spdlog registry; filename is provided as parameter in enable_logging
+ const Real total_items_persistence;
+ const Real total_bidders_persistence;
+ Real partial_cost;
+ Real unassigned_bidders_persistence;
+ Real unassigned_items_persistence;
+#endif
+};
+
+} // ws
+} // hera
+
+
+#include "auction_runner_gs_single_diag.hpp"
+
+#endif
diff --git a/wasserstein/include/auction_runner_gs_single_diag.hpp b/wasserstein/include/auction_runner_gs_single_diag.hpp
new file mode 100644
index 0000000..a3c401e
--- /dev/null
+++ b/wasserstein/include/auction_runner_gs_single_diag.hpp
@@ -0,0 +1,738 @@
+/*
+
+Copyright (c) 2016, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+
+#include <assert.h>
+#include <stdexcept>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <chrono>
+
+#include "def_debug_ws.h"
+
+#define PRINT_DETAILED_TIMING
+
+#ifdef FOR_R_TDA
+#include "Rcpp.h"
+#undef DEBUG_AUCTION
+#endif
+
+
+namespace hera {
+namespace ws {
+
+// *****************************
+// AuctionRunnerGaussSeidelSingleDiag
+// *****************************
+
+template<class R, class AO>
+std::ostream& operator<<(std::ostream& s, const AuctionRunnerGaussSeidelSingleDiag<R, AO>& ar)
+{
+ s << "--------------------------------------------------\n";
+ s << "AuctionRunnerGaussSeidelSingleDiag, current assignment, bidders_to_items:" << std::endl;
+ for(size_t idx = 0; idx < ar.bidders_to_items.size(); ++idx) {
+ s << idx << " <--> " << ar.bidders_to_items[idx] << std::endl;
+ }
+ s << "--------------------------------------------------\n";
+ s << "AuctionRunnerGaussSeidelSingleDiag, current assignment, items_to_bidders:" << std::endl;
+ for(size_t idx = 0; idx < ar.items_to_bidders.size(); ++idx) {
+ s << idx << " <--> " << ar.items_to_bidders[idx] << std::endl;
+ }
+ s << "--------------------------------------------------\n";
+ s << "AuctionRunnerGaussSeidelSingleDiag, prices:" << std::endl;
+ for(size_t item_idx = 0; item_idx < ar.num_items; ++item_idx) {
+ s << item_idx << ": " << ar.oracle->get_price(item_idx) << std::endl;
+ }
+ s << "--------------------------------------------------\n";
+ s << "AuctionRunnerGaussSeidelSingleDiag, oracle :" << *(ar.oracle) << std::endl;
+ s << "--------------------------------------------------\n";
+ return s;
+}
+
+
+template<class R, class AO>
+AuctionRunnerGaussSeidelSingleDiag<R, AO>::AuctionRunnerGaussSeidelSingleDiag(const DgmPointVec& A,
+ const DgmPointVec& B,
+ const Real q,
+ const Real _delta,
+ const Real _internal_p,
+ const Real _initial_epsilon,
+ const Real _eps_factor,
+ const int _max_iter_num) :
+ bidders(A),
+ items(B),
+ num_bidders(A.size()),
+ num_items(B.size()),
+ items_to_bidders(B.size(), k_invalid_index),
+ bidders_to_items(A.size(), k_invalid_index),
+ wasserstein_power(q),
+ delta(_delta),
+ internal_p(_internal_p),
+ initial_epsilon(_initial_epsilon),
+ epsilon_common_ratio(_eps_factor == 0.0 ? 5.0 : _eps_factor),
+ max_iter_num(_max_iter_num)
+#ifdef LOG_AUCTION
+ , total_items_persistence(std::accumulate(items.begin(),
+ items.end(),
+ R(0.0),
+ [_internal_p, q](const Real& ps, const DgmPoint& item)
+ { return ps + std::pow(item.persistence_lp(_internal_p), q); }
+ ))
+
+ , total_bidders_persistence(std::accumulate(bidders.begin(),
+ bidders.end(),
+ R(0.0),
+ [_internal_p, q](const Real& ps, const DgmPoint& bidder)
+ { return ps + std::pow(bidder.persistence_lp(_internal_p), q); }
+ ))
+ , partial_cost(0.0)
+ , unassigned_bidders_persistence(0.0)
+ , unassigned_items_persistence(0.0)
+#endif
+
+{
+ assert(initial_epsilon >= 0.0 );
+ assert(epsilon_common_ratio >= 0.0 );
+ assert(A.size() == B.size());
+ oracle = std::unique_ptr<AuctionOracle>(new AuctionOracle(bidders, items, wasserstein_power, internal_p));
+
+ for(num_normal_bidders = 0; num_normal_bidders < num_bidders; ++num_normal_bidders) {
+ if (bidders[num_normal_bidders].is_diagonal())
+ break;
+ }
+
+ num_diag_bidders = num_bidders - num_normal_bidders;
+ num_diag_items = num_normal_bidders;
+ num_normal_items = num_items - num_diag_items;
+
+ for(size_t i = num_normal_bidders; i < num_bidders; ++i) {
+ assert(bidders[i].is_diagonal());
+ }
+
+#ifdef LOG_AUCTION
+
+ unassigned_items_persistence = total_items_persistence;
+ unassigned_bidders_persistence = total_bidders_persistence;
+
+ if (not spdlog::get("plot_logger")) {
+ auto log = spdlog::basic_logger_st("plot_logger", "plot_logger.txt");
+ log->info("New plot starts here");
+ log->set_pattern("%v");
+ }
+#endif
+
+}
+
+#ifdef LOG_AUCTION
+template<class R, class AO>
+void AuctionRunnerGaussSeidelSingleDiag<R, AO>::enable_logging(const char* log_filename, const size_t _max_unassigned_to_log)
+{
+ log_auction = true;
+ max_unassigned_to_log = _max_unassigned_to_log;
+
+ auto log = spdlog::basic_logger_st(logger_name, log_filename);
+ log->set_pattern("%v");
+}
+#endif
+
+template<class R, class AO>
+void AuctionRunnerGaussSeidelSingleDiag<R, AO>::process_diagonal_bid(const DiagonalBidR& bid)
+{
+
+ //std::cout << "Enter process_diagonal_bid, bid = " << bid << std::endl;
+
+ // increase price of already assigned normal items
+ for(size_t k = 0; k < bid.assigned_normal_items.size(); ++k) {
+ size_t assigned_normal_item_idx = bid.assigned_normal_items[k];
+ Real new_price = bid.assigned_normal_items_bid_values[k];
+ bool item_is_diagonal = false;
+ bool bidder_is_diagonal = true;
+
+ // TODO: SPECIAL PROCEDURE HEER`
+ oracle->set_price(assigned_normal_item_idx, new_price, item_is_diagonal, bidder_is_diagonal, OwnerType::k_diagonal);
+ }
+
+ // set common diag-diag price
+ // if diag_assigned_to_diag_slice_ is empty, it will be
+ // numeric_limits<Real>::max()
+
+ oracle->diag_to_diag_price_ = bid.diag_to_diag_value;
+
+ int unassigned_diag_idx = 0;
+ auto unassigned_diag_item_iter = oracle->diag_unassigned_slice_.begin();
+ auto bid_vec_idx = 0;
+ for(const auto diag_bidder_idx : unassigned_diag_bidders) {
+ if (unassigned_diag_idx < bid.num_from_unassigned_diag) {
+ // take diagonal point from unassigned slice
+
+ //std::cout << "assigning to diag_bidder_idx = " << diag_bidder_idx << std::endl;
+ assert(unassigned_diag_item_iter != oracle->diag_unassigned_slice_.end());
+
+ auto item_idx = *unassigned_diag_item_iter;
+
+ ++unassigned_diag_idx;
+ ++unassigned_diag_item_iter;
+ assign_item_to_bidder(item_idx, diag_bidder_idx, k_invalid_index, true, true, false);
+ } else {
+ // take point from best_item_indices
+ size_t item_idx = bid.best_item_indices[bid_vec_idx];
+ Real new_price = bid.bid_values[bid_vec_idx];
+ bid_vec_idx++;
+
+ auto old_owner_idx = items_to_bidders[item_idx];
+ bool item_is_diagonal = is_item_diagonal(item_idx);
+
+ assign_item_to_bidder(item_idx, diag_bidder_idx, old_owner_idx, item_is_diagonal, true, true, new_price);
+ }
+ }
+
+ // all bids of diagonal bidders are satisfied
+ unassigned_diag_bidders.clear();
+
+ if (oracle->diag_unassigned_slice_.empty()) {
+ oracle->diag_unassigned_price_ = std::numeric_limits<Real>::max();
+ }
+
+ //std::cout << "Exit process_diagonal_bid\n" << *this;
+}
+
+template<class R, class AO>
+bool AuctionRunnerGaussSeidelSingleDiag<R, AO>::is_bidder_diagonal(const size_t bidder_idx) const
+{
+ return bidder_idx >= num_normal_bidders;
+}
+
+template<class R, class AO>
+bool AuctionRunnerGaussSeidelSingleDiag<R, AO>::is_bidder_normal(const size_t bidder_idx) const
+{
+ return bidder_idx < num_normal_bidders;
+}
+
+template<class R, class AO>
+bool AuctionRunnerGaussSeidelSingleDiag<R, AO>::is_item_diagonal(const size_t item_idx) const
+{
+ return item_idx < num_diag_items;
+}
+
+template<class R, class AO>
+bool AuctionRunnerGaussSeidelSingleDiag<R, AO>::is_item_normal(const size_t item_idx) const
+{
+ return item_idx >= num_diag_items;
+}
+
+template<class R, class AO>
+void AuctionRunnerGaussSeidelSingleDiag<R, AO>::assign_item_to_bidder(const IdxType item_idx,
+ const IdxType bidder_idx,
+ const IdxType old_owner_idx,
+ const bool item_is_diagonal,
+ const bool bidder_is_diagonal,
+ const bool call_set_price,
+ const R new_price)
+{
+ //std::cout << "Enter assign_item_to_bidder, " << std::boolalpha ;
+ //std::cout << "item_idx = " << item_idx << ", bidder_idx = " << bidder_idx << ", old_owner_idx = " << old_owner_idx << ", item_is_diagonal = " << item_is_diagonal << ", bidder_is_diagonal = " << bidder_is_diagonal << std::endl;
+ //std::cout << "################################################################################" << std::endl;
+ //std::cout << *this << std::endl;
+ //std::cout << *(this->oracle) << std::endl;
+ //std::cout << "################################################################################" << std::endl;
+ num_rounds++;
+
+ // for readability
+ const bool item_is_normal = not item_is_diagonal;
+ const bool bidder_is_normal = not bidder_is_diagonal;
+
+ // only unassigned bidders should submit bids and get items
+ assert(bidders_to_items[bidder_idx] == k_invalid_index);
+
+
+ // update matching information
+ bidders_to_items[bidder_idx] = item_idx;
+ items_to_bidders[item_idx] = bidder_idx;
+
+
+ // remove bidder from the list of unassigned bidders
+ // for diagonal bidders we don't need to: in Gauss-Seidel they are all
+ // processed at once, so the set unassigned_diag_bidders will be cleared
+ if (bidder_is_normal) {
+ unassigned_normal_bidders.erase(bidder_idx);
+ }
+
+ OwnerType old_owner_type = get_owner_type(old_owner_idx);
+
+ if (old_owner_type != OwnerType::k_none) {
+ bidders_to_items[old_owner_idx] = k_invalid_index;
+ }
+
+ switch(old_owner_type)
+ {
+ case OwnerType::k_normal : unassigned_normal_bidders.insert(old_owner_idx);
+ break;
+ case OwnerType::k_diagonal : unassigned_diag_bidders.insert(old_owner_idx);
+ break;
+ case OwnerType::k_none : break;
+ }
+
+
+ // update normal_items_assigned_to_diag_
+
+ if (old_owner_type == OwnerType::k_diagonal and item_is_normal and bidder_is_normal) {
+ // normal item was stolen from diagonal, erase
+ assert( oracle->normal_items_assigned_to_diag_.count(item_idx) == 1 );
+ oracle->normal_items_assigned_to_diag_.erase(item_idx);
+ } else if (bidder_is_diagonal and item_is_normal and old_owner_type != OwnerType::k_diagonal) {
+ // diagonal bidder got a new normal item, insert
+ assert(oracle->normal_items_assigned_to_diag_.count(item_idx) == 0);
+ oracle->normal_items_assigned_to_diag_.insert(item_idx);
+ }
+
+
+ // update diag_assigned_to_diag_slice_
+ if (item_is_diagonal and bidder_is_normal and old_owner_type == OwnerType::k_diagonal) {
+ assert( oracle->diag_assigned_to_diag_slice_.count(item_idx) == 1);
+ oracle->diag_assigned_to_diag_slice_.erase(item_idx);
+ } else if (item_is_diagonal and bidder_is_diagonal) {
+ assert( old_owner_type != OwnerType::k_diagonal ); // diagonal does not steal from itself
+ assert( oracle->diag_assigned_to_diag_slice_.count(item_idx) == 0);
+ oracle->diag_assigned_to_diag_slice_.insert(item_idx);
+ }
+
+ // update diag_unassigned_slice_
+ if (item_is_diagonal and old_owner_type == OwnerType::k_none) {
+ oracle->diag_unassigned_slice_.erase(item_idx);
+ }
+
+ if ( not (not call_set_price or new_price != std::numeric_limits<R>::max())) {
+ std::cout << "In the middle of assign_item_to_bidder, " << std::boolalpha ;
+ std::cout << "item_idx = " << item_idx << ", bidder_idx = " << bidder_idx << ", old_owner_idx = " << old_owner_idx << ", item_is_diagonal = " << item_is_diagonal << ", bidder_is_diagonal = " << bidder_is_diagonal << std::endl;
+ std::cout << "################################################################################" << std::endl;
+ std::cout << *this << std::endl;
+ std::cout << "################################################################################" << std::endl;
+ }
+ assert(not call_set_price or new_price != std::numeric_limits<R>::max());
+ if (call_set_price) {
+ oracle->set_price(item_idx, new_price, item_is_diagonal, bidder_is_diagonal, old_owner_type);
+ }
+
+ //std::cout << "Exit assign_item_to_bidder, state\n" << *this << std::endl;
+
+#ifdef LOG_AUCTION
+
+ partial_cost += get_item_bidder_cost(item_idx, bidder_idx, true);
+ partial_cost -= get_item_bidder_cost(item_idx, old_owner_idx, true);
+
+ unassigned_items.erase(item_idx);
+
+ unassigned_bidders_persistence -= std::pow(bidders[bidder_idx].persistence_lp(internal_p), wasserstein_power);
+
+ if (old_owner_type != OwnerType::k_none) {
+ // item has been assigned to some other bidder,
+ // and he became unassigned
+ unassigned_bidders_persistence += std::pow(bidders[old_owner_idx].persistence_lp(internal_p), wasserstein_power);
+ } else {
+ // item was unassigned before
+ unassigned_items_persistence -= std::pow(items[item_idx].persistence_lp(internal_p), wasserstein_power);
+ }
+
+ auto plot_logger = spdlog::get("plot_logger");
+ plot_logger->info("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10}",
+ num_phase,
+ num_rounds,
+ unassigned_normal_bidders.size(),
+ unassigned_diag_bidders.size(),
+ unassigned_items_persistence,
+ unassigned_bidders_persistence,
+ unassigned_items_persistence + unassigned_bidders_persistence,
+ partial_cost,
+ total_bidders_persistence,
+ total_items_persistence,
+ oracle->get_epsilon()
+ );
+
+
+ if (log_auction and unassigned_normal_bidders.size() + unassigned_diag_bidders.size() <= max_unassigned_to_log) {
+ auto logger = spdlog::get(logger_name);
+ if (logger) {
+ auto item = items[item_idx];
+ auto bidder = bidders[bidder_idx];
+ logger->info("{0} # ({1}, {2}) # ({3}, {4}) # {5} # {6} # {7} # {8}",
+ num_rounds,
+ item.getRealX(),
+ item.getRealY(),
+ bidder.getRealX(),
+ bidder.getRealY(),
+ format_point_set_to_log(unassigned_diag_bidders, bidders),
+ format_point_set_to_log(unassigned_normal_bidders, bidders),
+ format_point_set_to_log(unassigned_items, items),
+ oracle->get_epsilon());
+ }
+ }
+#endif
+}
+
+
+
+template<class R, class AO>
+void AuctionRunnerGaussSeidelSingleDiag<R, AO>::flush_assignment()
+{
+ for(auto& b2i : bidders_to_items) {
+ b2i = k_invalid_index;
+ }
+ for(auto& i2b : items_to_bidders) {
+ i2b = k_invalid_index;
+ }
+
+ // we must flush assignment only after we got perfect matching
+ assert(unassigned_normal_bidders.empty() and unassigned_diag_bidders.empty());
+ // all bidders become unassigned
+ for(size_t bidder_idx = 0; bidder_idx < num_normal_bidders; ++bidder_idx) {
+ unassigned_normal_bidders.insert(bidder_idx);
+ }
+ for(size_t bidder_idx = num_normal_bidders; bidder_idx < num_bidders; ++bidder_idx) {
+ unassigned_diag_bidders.insert(bidder_idx);
+ }
+ assert(unassigned_normal_bidders.size() + unassigned_diag_bidders.size() == bidders.size());
+ assert(unassigned_normal_bidders.size() == num_normal_bidders);
+ assert(unassigned_diag_bidders.size() == num_diag_bidders);
+
+ oracle->flush_assignment();
+ oracle->adjust_prices();
+
+#ifdef LOG_AUCTION
+ partial_cost = 0.0;
+ unassigned_bidders_persistence = total_bidders_persistence;
+ unassigned_items_persistence = total_items_persistence;
+
+ for(size_t item_idx = 0; item_idx < items.size(); ++item_idx) {
+ unassigned_items.insert(item_idx);
+ }
+#endif
+
+}
+
+
+template<class R, class AO>
+void AuctionRunnerGaussSeidelSingleDiag<R, AO>::run_auction_phases(const int max_num_phases, const Real _initial_epsilon)
+{
+ relative_error = std::numeric_limits<Real>::max();
+ // choose some initial epsilon
+ oracle->set_epsilon(_initial_epsilon);
+ assert( oracle->get_epsilon() > 0 );
+ for(int phase_num = 0; phase_num < max_num_phases; ++phase_num) {
+ flush_assignment();
+ run_auction_phase();
+ phase_num++;
+ //std::cout << "Iteration " << phase_num << " completed. " << std::endl;
+ // result is d^q
+ Real current_result = getDistanceToQthPowerInternal();
+ Real denominator = current_result - num_bidders * oracle->get_epsilon();
+ current_result = pow(current_result, 1.0 / wasserstein_power);
+ //std::cout << "Current result is " << current_result << std::endl;
+ if ( denominator <= 0 ) {
+ //std::cout << "Epsilon is too big." << std::endl;
+ } else {
+ denominator = pow(denominator, 1.0 / wasserstein_power);
+ Real numerator = current_result - denominator;
+ relative_error = numerator / denominator;
+ //std::cout << " numerator: " << numerator << " denominator: " << denominator << std::endl;
+ //std::cout << " error bound: " << numerator / denominator << std::endl;
+ // if relative error is greater than delta, continue
+ if (relative_error <= delta) {
+ break;
+ }
+ }
+ // decrease epsilon for the next iteration
+ oracle->set_epsilon( oracle->get_epsilon() / epsilon_common_ratio );
+ }
+ //print_matching();
+}
+
+
+template<class R, class AO>
+void AuctionRunnerGaussSeidelSingleDiag<R, AO>::run_auction()
+{
+ double init_eps = ( initial_epsilon > 0.0 ) ? initial_epsilon : oracle->max_val_ / 4.0 ;
+ run_auction_phases(max_iter_num, init_eps);
+ if (relative_error > delta) {
+#ifndef FOR_R_TDA
+ std::cerr << "Maximum iteration number exceeded, exiting. Current result is: ";
+ std::cerr << pow(wasserstein_cost, 1.0/wasserstein_power) << std::endl;
+#endif
+ throw std::runtime_error("Maximum iteration number exceeded");
+ }
+}
+
+template<class R, class AO>
+OwnerType AuctionRunnerGaussSeidelSingleDiag<R, AO>::get_owner_type(size_t bidder_idx) const
+{
+ if (bidder_idx == k_invalid_index) {
+ return OwnerType::k_none;
+ } else if (is_bidder_diagonal(bidder_idx)) {
+ return OwnerType::k_diagonal;
+ } else {
+ return OwnerType::k_normal;
+ }
+}
+
+template<class R, class AO>
+void AuctionRunnerGaussSeidelSingleDiag<R, AO>::run_auction_phase()
+{
+ num_phase++;
+ //std::cout << "Entered run_auction_phase" << std::endl;
+ do {
+
+ if (not unassigned_diag_bidders.empty()) {
+ // process all unassigned diagonal bidders
+ // easy for Gauss-Seidel: every bidder alwasy gets all he wants
+ //
+ sanity_check();
+ //std::cout << "Current state " << __LINE__ << *this << std::endl;
+ process_diagonal_bid(oracle->get_optimal_bids_for_diagonal( unassigned_diag_bidders.size() ));
+ sanity_check();
+ } else {
+ sanity_check();
+ // process normal unassigned bidder
+ size_t bidder_idx = *(unassigned_normal_bidders.begin());
+ auto optimal_bid = oracle->get_optimal_bid(bidder_idx);
+ auto optimal_item_idx = optimal_bid.first;
+ auto bid_value = optimal_bid.second;
+ bool item_is_diagonal = is_item_diagonal(optimal_item_idx);
+ size_t old_owner_idx = items_to_bidders[optimal_item_idx];
+
+ //OwnerType old_owner_type = get_owner_type(old_owner_idx);
+ //std::cout << "bidder_idx = " << bidder_idx << ", item_idx = " << optimal_item_idx << ", old_owner_type = " << old_owner_type << std::endl;
+
+ assign_item_to_bidder(optimal_item_idx, bidder_idx, old_owner_idx, item_is_diagonal, false, true, bid_value);
+ sanity_check();
+ }
+
+#ifdef FOR_R_TDA
+ if ( num_rounds % 10000 == 0 ) {
+ Rcpp::check_user_interrupt();
+ }
+#endif
+ } while (not (unassigned_diag_bidders.empty() and unassigned_normal_bidders.empty()));
+ //std::cout << "run_auction_phase finished" << std::endl;
+
+#ifdef DEBUG_AUCTION
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ if ( bidders_to_items[bidder_idx] < 0 or bidders_to_items[bidder_idx] >= (IdxType)num_bidders) {
+ std::cerr << "After auction terminated bidder " << bidder_idx;
+ std::cerr << " has no items assigned" << std::endl;
+ throw std::runtime_error("Auction did not give a perfect matching");
+ }
+ }
+#endif
+
+}
+
+template<class R, class AO>
+R AuctionRunnerGaussSeidelSingleDiag<R, AO>::get_item_bidder_cost(size_t item_idx, size_t bidder_idx, const bool tolerate_invalid_idx) const
+{
+ if (item_idx != k_invalid_index and bidder_idx != k_invalid_index) {
+ // skew edges are replaced by edges to projection
+ if (is_bidder_diagonal(bidder_idx) and is_item_normal(item_idx)) {
+ bidder_idx = item_idx;
+ } else if (is_bidder_normal(bidder_idx) and is_item_diagonal(item_idx)) {
+ item_idx = bidder_idx;
+ }
+ return std::pow(dist_lp(bidders[bidder_idx], items[item_idx], internal_p),
+ wasserstein_power);
+ } else {
+ if (tolerate_invalid_idx)
+ return R(0.0);
+ else
+ throw std::runtime_error("Invalid idx in get_item_bidder_cost, item_idx = " + std::to_string(item_idx) + ", bidder_idx = " + std::to_string(bidder_idx));
+ }
+}
+
+template<class R, class AO>
+R AuctionRunnerGaussSeidelSingleDiag<R, AO>::getDistanceToQthPowerInternal()
+{
+ sanity_check();
+ Real result = 0.0;
+ for(size_t bIdx = 0; bIdx < num_bidders; ++bIdx) {
+ result += get_item_bidder_cost(bidders_to_items[bIdx], bIdx);
+ }
+ wasserstein_cost = result;
+ return result;
+}
+
+template<class R, class AO>
+R AuctionRunnerGaussSeidelSingleDiag<R, AO>::get_wasserstein_distance()
+{
+ return pow(get_wasserstein_cost(), 1.0/wasserstein_power);
+}
+
+template<class R, class AO>
+R AuctionRunnerGaussSeidelSingleDiag<R, AO>::get_wasserstein_cost()
+{
+ run_auction();
+ return wasserstein_cost;
+}
+
+
+
+// Debug routines
+
+
+template<class R, class AO>
+void AuctionRunnerGaussSeidelSingleDiag<R, AO>::print_debug()
+{
+#ifdef DEBUG_AUCTION
+ std::cout << "**********************" << std::endl;
+ std::cout << "Current assignment:" << std::endl;
+ for(size_t idx = 0; idx < bidders_to_items.size(); ++idx) {
+ std::cout << idx << " <--> " << bidders_to_items[idx] << std::endl;
+ }
+ std::cout << "Weights: " << std::endl;
+ //for(size_t i = 0; i < num_bidders; ++i) {
+ //for(size_t j = 0; j < num_items; ++j) {
+ //std::cout << oracle->weight_matrix[i][j] << " ";
+ //}
+ //std::cout << std::endl;
+ //}
+ std::cout << "Prices: " << std::endl;
+ for(const auto price : oracle->get_prices()) {
+ std::cout << price << std::endl;
+ }
+ std::cout << "**********************" << std::endl;
+#endif
+}
+
+
+template<class R, class AO>
+void AuctionRunnerGaussSeidelSingleDiag<R, AO>::sanity_check()
+{
+#ifdef DEBUG_AUCTION
+ if (bidders_to_items.size() != num_bidders) {
+ std::cerr << "Wrong size of bidders_to_items, must be " << num_bidders << ", is " << bidders_to_items.size() << std::endl;
+ throw std::runtime_error("Wrong size of bidders_to_items");
+ }
+
+ if (items_to_bidders.size() != num_bidders) {
+ std::cerr << "Wrong size of items_to_bidders, must be " << num_bidders << ", is " << items_to_bidders.size() << std::endl;
+ throw std::runtime_error("Wrong size of items_to_bidders");
+ }
+
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ assert( bidders_to_items[bidder_idx] == k_invalid_index or ( bidders_to_items[bidder_idx] < static_cast<IdxType>(num_items) and bidders_to_items[bidder_idx] >= 0));
+
+ if ( bidders_to_items[bidder_idx] != k_invalid_index) {
+
+ if ( std::count(bidders_to_items.begin(),
+ bidders_to_items.end(),
+ bidders_to_items[bidder_idx]) > 1 ) {
+ std::cerr << "Item " << bidders_to_items[bidder_idx];
+ std::cerr << " appears in bidders_to_items more than once" << std::endl;
+ throw std::runtime_error("Duplicate in bidders_to_items");
+ }
+
+ if (items_to_bidders.at(bidders_to_items[bidder_idx]) != static_cast<int>(bidder_idx)) {
+ std::cerr << "Inconsitency: bidder_idx = " << bidder_idx;
+ std::cerr << ", item_idx in bidders_to_items = ";
+ std::cerr << bidders_to_items[bidder_idx];
+ std::cerr << ", bidder_idx in items_to_bidders = ";
+ std::cerr << items_to_bidders[bidders_to_items[bidder_idx]] << std::endl;
+ throw std::runtime_error("inconsistent mapping");
+ }
+ }
+ }
+
+ for(size_t item_idx = 0; item_idx < num_diag_items; ++item_idx) {
+ auto owner = items_to_bidders.at(item_idx);
+ if ( owner == k_invalid_index) {
+ assert((oracle->diag_unassigned_slice_.count(item_idx) == 1 and
+ oracle->diag_items_heap__iters_[item_idx] == oracle->diag_items_heap_.end() and
+ oracle->all_items_heap__iters_[item_idx] == oracle->all_items_heap_.end())
+ or
+ (oracle->diag_unassigned_slice_.count(item_idx) == 0 and
+ oracle->diag_items_heap__iters_[item_idx] != oracle->diag_items_heap_.end() and
+ oracle->all_items_heap__iters_[item_idx] != oracle->all_items_heap_.end()));
+ assert(oracle->diag_assigned_to_diag_slice_.count(item_idx) == 0);
+ } else {
+ if (is_bidder_diagonal(owner)) {
+ assert(oracle->diag_unassigned_slice_.count(item_idx) == 0);
+ assert(oracle->diag_assigned_to_diag_slice_.count(item_idx) == 1);
+ assert(oracle->diag_items_heap__iters_[item_idx] == oracle->diag_items_heap_.end());
+ assert(oracle->all_items_heap__iters_[item_idx] == oracle->all_items_heap_.end());
+ } else {
+ assert(oracle->diag_unassigned_slice_.count(item_idx) == 0);
+ assert(oracle->diag_assigned_to_diag_slice_.count(item_idx) == 0);
+ assert(oracle->diag_items_heap__iters_[item_idx] != oracle->diag_items_heap_.end());
+ assert(oracle->all_items_heap__iters_[item_idx] != oracle->all_items_heap_.end());
+ }
+ }
+ }
+
+ for(IdxType item_idx = 0; item_idx < static_cast<IdxType>(num_bidders); ++item_idx) {
+ assert( items_to_bidders[item_idx] == k_invalid_index or ( items_to_bidders[item_idx] < static_cast<IdxType>(num_items) and items_to_bidders[item_idx] >= 0));
+ if ( items_to_bidders.at(item_idx) != k_invalid_index) {
+
+ // check for uniqueness
+ if ( std::count(items_to_bidders.begin(),
+ items_to_bidders.end(),
+ items_to_bidders[item_idx]) > 1 ) {
+ std::cerr << "Bidder " << items_to_bidders[item_idx];
+ std::cerr << " appears in items_to_bidders more than once" << std::endl;
+ throw std::runtime_error("Duplicate in items_to_bidders");
+ }
+ // check for consistency
+ if (bidders_to_items.at(items_to_bidders.at(item_idx)) != static_cast<int>(item_idx)) {
+ std::cerr << "Inconsitency: item_idx = " << item_idx;
+ std::cerr << ", bidder_idx in items_to_bidders = ";
+ std::cerr << items_to_bidders[item_idx];
+ std::cerr << ", item_idx in bidders_to_items= ";
+ std::cerr << bidders_to_items[items_to_bidders[item_idx]] << std::endl;
+ throw std::runtime_error("inconsistent mapping");
+ }
+ }
+ }
+
+ oracle->sanity_check();
+#endif
+}
+
+template<class R, class AO>
+void AuctionRunnerGaussSeidelSingleDiag<R, AO>::print_matching()
+{
+#ifdef DEBUG_AUCTION
+ sanity_check();
+ for(size_t bIdx = 0; bIdx < bidders_to_items.size(); ++bIdx) {
+ if (bidders_to_items[bIdx] != k_invalid_index) {
+ auto pA = bidders[bIdx];
+ auto pB = items[bidders_to_items[bIdx]];
+ std::cout << pA << " <-> " << pB << "+" << pow(dist_lp(pA, pB, internal_p), wasserstein_power) << std::endl;
+ } else {
+ assert(false);
+ }
+ }
+#endif
+}
+
+} // ws
+} // hera
diff --git a/wasserstein/include/auction_runner_jac.h b/wasserstein/include/auction_runner_jac.h
new file mode 100644
index 0000000..252ca32
--- /dev/null
+++ b/wasserstein/include/auction_runner_jac.h
@@ -0,0 +1,230 @@
+/*
+
+Copyright (c) 2016, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef HERA_AUCTION_RUNNER_JAC_H
+#define HERA_AUCTION_RUNNER_JAC_H
+
+#ifdef WASSERSTEIN_PURE_GEOM
+#undef LOG_AUCTION
+#undef ORDERED_BY_PERSISTENCE
+#endif
+
+//#define ORDERED_BY_PERSISTENCE
+
+#include <unordered_set>
+
+#include "auction_oracle.h"
+
+namespace hera {
+namespace ws {
+
+// the two parameters that you can tweak in auction algorithm are:
+// 1. epsilon_common_ratio
+// 2. max_num_phases
+
+template<class RealType_ = double, class AuctionOracle_ = AuctionOracleKDTreeRestricted<RealType_>, class PointContainer_ = std::vector<DiagramPoint<RealType_>> > // alternatively: AuctionOracleLazyHeap --- TODO
+class AuctionRunnerJac {
+public:
+
+ using Real = RealType_;
+ using AuctionOracle = AuctionOracle_;
+ using DgmPoint = typename AuctionOracle::DiagramPointR;
+ using IdxValPairR = IdxValPair<Real>;
+ using PointContainer = PointContainer_;
+
+ const Real k_lowest_bid_value = -1; // all bid values must be positive
+
+
+ AuctionRunnerJac(const PointContainer& A,
+ const PointContainer& B,
+ const AuctionParams<Real>& params,
+ const std::string& _log_filename_prefix = "");
+
+ void set_epsilon(Real new_val);
+ Real get_epsilon() const { return epsilon; }
+ void run_auction();
+ template<class Range>
+ void run_bidding_step(const Range& r);
+ bool is_done() const;
+ void decrease_epsilon();
+ Real get_wasserstein_distance();
+ Real get_wasserstein_cost();
+ Real get_relative_error(const bool debug_output = false) const;
+//private:
+ // private data
+ PointContainer bidders;
+ PointContainer items;
+ const size_t num_bidders;
+ const size_t num_items;
+ std::vector<IdxType> items_to_bidders;
+ std::vector<IdxType> bidders_to_items;
+ Real wasserstein_power;
+ Real epsilon;
+ Real delta;
+ Real internal_p;
+ Real initial_epsilon;
+ const Real epsilon_common_ratio; // next epsilon = current epsilon / epsilon_common_ratio
+ const int max_num_phases; // maximal number of phases of epsilon-scaling
+ Real weight_adj_const;
+ Real wasserstein_cost;
+ std::vector<IdxValPairR> bid_table;
+ // to get the 2 best items
+ AuctionOracle oracle;
+ std::unordered_set<size_t> unassigned_bidders;
+ std::unordered_set<size_t> items_with_bids;
+ // to imitate Gauss-Seidel
+ const size_t max_bids_per_round;
+ Real partial_cost { 0.0 };
+ bool is_distance_computed { false };
+ int num_rounds { 0 };
+ int num_phase { 0 };
+ int dimension;
+
+ size_t unassigned_threshold; // for experiments
+
+#ifndef WASSERSTEIN_PURE_GEOM
+ std::unordered_set<size_t> unassigned_normal_bidders;
+ std::unordered_set<size_t> unassigned_diag_bidders;
+ bool diag_first {true};
+ size_t batch_size { 1000 };
+#ifdef ORDERED_BY_PERSISTENCE
+ // to process unassigned by persistence
+ using RealIdxPair = std::pair<Real, size_t>;
+ std::set<RealIdxPair, std::greater<RealIdxPair>> unassigned_normal_bidders_by_persistence;
+#endif
+
+ // to stop earlier in the last phase
+ const Real total_items_persistence;
+ const Real total_bidders_persistence;
+ Real unassigned_bidders_persistence;
+ Real unassigned_items_persistence;
+ Real gamma_threshold;
+
+
+ size_t num_diag_items { 0 };
+ size_t num_normal_items { 0 };
+ size_t num_diag_bidders { 0 };
+ size_t num_normal_bidders { 0 };
+
+
+#endif
+
+
+
+ // private methods
+ void assign_item_to_bidder(const IdxType bidder_idx, const IdxType items_idx);
+ void assign_to_best_bidder(const IdxType items_idx);
+ void clear_bid_table();
+ void run_auction_phases(const int max_num_phases, const Real _initial_epsilon);
+ void run_auction_phase();
+ void submit_bid(IdxType bidder_idx, const IdxValPairR& items_bid_value_pair);
+ void flush_assignment();
+ Real get_item_bidder_cost(const size_t item_idx, const size_t bidder_idx) const;
+#ifndef WASSERSTEIN_PURE_GEOM
+ Real get_cost_to_diagonal(const DgmPoint& pt) const;
+ Real get_gamma() const;
+#endif
+ bool continue_auction_phase() const;
+
+ void add_unassigned_bidder(const size_t bidder_idx);
+ void remove_unassigned_bidder(const size_t bidder_idx);
+ void remove_unassigned_item(const size_t item_idx);
+
+#ifndef WASSERSTEIN_PURE_GEOM
+ bool is_item_diagonal(const size_t item_idx) const { return item_idx < num_diag_items; }
+ bool is_item_normal(const size_t item_idx) const { return not is_item_diagonal(item_idx); }
+ bool is_bidder_diagonal(const size_t bidder_idx) const { return bidder_idx >= num_normal_bidders; }
+ bool is_bidder_normal(const size_t bidder_idx) const { return not is_bidder_diagonal(bidder_idx); }
+#endif
+
+
+
+ // for debug only
+ void sanity_check();
+ void print_debug();
+ void print_matching();
+
+ std::string log_filename_prefix;
+ const Real k_max_relative_error = 2.0; // if relative error cannot be estimated or is too large, use this value
+
+#ifdef LOG_AUCTION
+
+ size_t parallel_threshold { 5000 };
+ bool is_step_parallel {false};
+ std::unordered_set<size_t> unassigned_items;
+ std::unordered_set<size_t> unassigned_normal_items;
+ std::unordered_set<size_t> unassigned_diag_items;
+ std::unordered_set<size_t> never_assigned_bidders;
+ size_t all_assigned_round { 0 };
+ size_t all_assigned_round_found { false };
+
+ int num_rounds_non_cumulative { 0 }; // set to 0 in the beginning of each phase
+ int num_diag_assignments { 0 };
+ int num_diag_assignments_non_cumulative { 0 };
+ int num_diag_bids_submitted { 0 };
+ int num_diag_stole_from_diag { 0 };
+ int num_normal_assignments { 0 };
+ int num_normal_assignments_non_cumulative { 0 };
+ int num_normal_bids_submitted { 0 };
+
+ std::vector<std::vector<size_t>> price_change_cnt_vec;
+
+
+ const char* plot_logger_name = "plot_logger";
+ const char* price_state_logger_name = "price_stat_logger";
+ std::string plot_logger_file_name;
+ std::string price_stat_logger_file_name;
+ std::shared_ptr<spdlog::logger> plot_logger;
+ std::shared_ptr<spdlog::logger> price_stat_logger;
+ std::shared_ptr<spdlog::logger> console_logger;
+
+
+ int num_parallel_bids { 0 };
+ int num_total_bids { 0 };
+
+ int num_parallel_diag_bids { 0 };
+ int num_total_diag_bids { 0 };
+
+ int num_parallel_normal_bids { 0 };
+ int num_total_normal_bids { 0 };
+
+ int num_parallel_assignments { 0 };
+ int num_total_assignments { 0 };
+#endif
+
+}; // AuctionRunnerJac
+
+
+} // ws
+} // hera
+
+#include "auction_runner_jac.hpp"
+
+#undef ORDERED_BY_PERSISTENCE
+
+#endif
diff --git a/wasserstein/include/auction_runner_jac.hpp b/wasserstein/include/auction_runner_jac.hpp
new file mode 100644
index 0000000..e623f4a
--- /dev/null
+++ b/wasserstein/include/auction_runner_jac.hpp
@@ -0,0 +1,879 @@
+/*
+
+Copyright (c) 2016, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+*/
+
+#ifndef AUCTION_RUNNER_JAC_HPP
+#define AUCTION_RUNNER_JAC_HPP
+
+#include <assert.h>
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+#include "def_debug_ws.h"
+#include "auction_runner_jac.h"
+
+
+#ifdef FOR_R_TDA
+#include "Rcpp.h"
+#undef DEBUG_AUCTION
+#endif
+
+namespace hera {
+namespace ws {
+
+
+// *****************************
+// AuctionRunnerJac
+// *****************************
+
+ template<class R, class AO, class PC>
+ AuctionRunnerJac<R, AO, PC>::AuctionRunnerJac(const PointContainer& A,
+ const PointContainer& B,
+ const AuctionParams<Real>& params,
+ const std::string &_log_filename_prefix
+ ) :
+ bidders(A),
+ items(B),
+ num_bidders(A.size()),
+ num_items(A.size()),
+ items_to_bidders(A.size(), k_invalid_index),
+ bidders_to_items(A.size(), k_invalid_index),
+ wasserstein_power(params.wasserstein_power),
+ delta(params.delta),
+ internal_p(params.internal_p),
+ initial_epsilon(params.initial_epsilon),
+ epsilon_common_ratio(params.epsilon_common_ratio == 0.0 ? 5.0 : params.epsilon_common_ratio),
+ max_num_phases(params.max_num_phases),
+ bid_table(A.size(), std::make_pair(k_invalid_index, k_lowest_bid_value)),
+ oracle(bidders, items, params),
+ max_bids_per_round(params.max_bids_per_round),
+ dimension(params.dim),
+#ifndef WASSERSTEIN_PURE_GEOM
+ total_items_persistence(std::accumulate(items.begin(),
+ items.end(),
+ R(0.0),
+ [params](const Real &ps, const DgmPoint &item) {
+ return ps + std::pow(item.persistence_lp(params.internal_p), params.wasserstein_power);
+ }
+ )),
+ total_bidders_persistence(std::accumulate(bidders.begin(),
+ bidders.end(),
+ R(0.0),
+ [params](const Real &ps, const DgmPoint &bidder) {
+ return ps + std::pow(bidder.persistence_lp(params.internal_p), params.wasserstein_power);
+ }
+ )),
+ unassigned_bidders_persistence(total_bidders_persistence),
+ unassigned_items_persistence(total_items_persistence),
+ gamma_threshold(params.gamma_threshold),
+#endif
+ log_filename_prefix(_log_filename_prefix)
+ {
+ assert(A.size() == B.size());
+
+#ifndef WASSERSTEIN_PURE_GEOM
+ for (const auto &p : bidders) {
+ if (p.is_normal()) {
+ num_normal_bidders++;
+ num_diag_items++;
+ } else {
+ num_normal_items++;
+ num_diag_bidders++;
+ }
+ }
+#endif
+ // for experiments
+ unassigned_threshold = 100;
+
+#ifdef ORDERED_BY_PERSISTENCE
+ batch_size = 1000;
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ if (is_bidder_normal(bidder_idx)) {
+ unassigned_normal_bidders_by_persistence.insert(
+ std::make_pair(bidders[bidder_idx].persistence_lp(1.0), bidder_idx));
+ }
+ }
+#endif
+
+#ifdef LOG_AUCTION
+ parallel_threshold = 16;
+ console_logger = spdlog::get("console");
+ if (not console_logger) {
+ console_logger = spdlog::stdout_logger_st("console");
+ }
+ console_logger->set_pattern("[%H:%M:%S.%e] %v");
+#ifdef ORDERED_BY_PERSISTENCE
+ if (max_bids_per_round == 1) {
+ console_logger->info("Gauss-Seidel imitated by Jacobi runner, q = {0}, max_bids_per_round = {1}, batch_size = {4}, gamma_threshold = {2}, diag_first = {3} ORDERED_BY_PERSISTENCE",
+ wasserstein_power,
+ max_bids_per_round,
+ gamma_threshold,
+ diag_first,
+ batch_size);
+ } else {
+ console_logger->info("Jacobi runner, q = {0}, max_bids_per_round = {1}, batch_size = {4}, gamma_threshold = {2}, diag_first = {3} ORDERED_BY_PERSISTENCE",
+ wasserstein_power,
+ max_bids_per_round,
+ gamma_threshold,
+ diag_first,
+ batch_size);
+ }
+
+#else
+ if (max_bids_per_round == 1) {
+ console_logger->info(
+ "Gauss-Seidel imitated by Jacobi runner, q = {0}, max_bids_per_round = {1}, batch_size = {4}, gamma_threshold = {2}, diag_first = {3}",
+ wasserstein_power,
+ max_bids_per_round,
+ gamma_threshold,
+ diag_first,
+ batch_size);
+ } else {
+ console_logger->info(
+ "Jacobi runner, q = {0}, max_bids_per_round = {1}, batch_size = {4}, gamma_threshold = {2}, diag_first = {3}",
+ wasserstein_power,
+ max_bids_per_round,
+ gamma_threshold,
+ diag_first,
+ batch_size);
+ }
+#endif
+
+ plot_logger_file_name = log_filename_prefix + "_plot.txt";
+ plot_logger = spdlog::get(plot_logger_name);
+ if (not plot_logger) {
+ plot_logger = spdlog::basic_logger_st(plot_logger_name, plot_logger_file_name);
+ }
+ plot_logger->info("New plot starts here, diagram size = {0}, gamma_threshold = {1}, epsilon_common_ratio = {2}",
+ bidders.size(),
+ gamma_threshold,
+ epsilon_common_ratio);
+ plot_logger->set_pattern("%v");
+
+ price_stat_logger_file_name = log_filename_prefix + "_price_change_stat";
+ price_stat_logger = spdlog::get(price_state_logger_name);
+ if (not price_stat_logger) {
+ price_stat_logger = spdlog::basic_logger_st(price_state_logger_name,
+ price_stat_logger_file_name);
+ }
+ price_stat_logger->info(
+ "New price statistics starts here, diagram size = {0}, gamma_threshold = {1}, epsilon_common_ratio = {2}",
+ bidders.size(),
+ gamma_threshold,
+ epsilon_common_ratio);
+ price_stat_logger->set_pattern("%v");
+#endif
+ }
+
+#ifndef WASSERSTEIN_PURE_GEOM
+ template<class R, class AO, class PC>
+ typename AuctionRunnerJac<R, AO, PC>::Real
+ AuctionRunnerJac<R, AO, PC>::get_cost_to_diagonal(const DgmPoint &pt) const {
+ return std::pow(pt.persistence_lp(internal_p), wasserstein_power);
+ }
+
+ template<class R, class AO, class PC>
+ typename AuctionRunnerJac<R, AO, PC>::Real
+ AuctionRunnerJac<R, AO, PC>::get_gamma() const {
+ return std::pow(std::fabs(unassigned_items_persistence + unassigned_bidders_persistence),
+ 1.0 / wasserstein_power);
+ }
+#endif
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::assign_item_to_bidder(IdxType item_idx, IdxType bidder_idx)
+ {
+ //sanity_check();
+ // only unassigned bidders submit bids
+ assert(bidders_to_items[bidder_idx] == k_invalid_index);
+
+ IdxType old_item_owner = items_to_bidders[item_idx];
+
+ // set new owner
+ bidders_to_items[bidder_idx] = item_idx;
+ items_to_bidders[item_idx] = bidder_idx;
+
+ // remove bidder and item from the sets of unassigned bidders/items
+ remove_unassigned_bidder(bidder_idx);
+
+ if (k_invalid_index != old_item_owner) {
+ // old owner of item becomes unassigned
+ bidders_to_items[old_item_owner] = k_invalid_index;
+ add_unassigned_bidder(old_item_owner);
+ // existing edge was removed, decrease partial_cost
+ partial_cost -= get_item_bidder_cost(item_idx, old_item_owner);
+ } else {
+ // item was unassigned before
+ remove_unassigned_item(item_idx);
+ }
+
+ // new edge was added to matching, increase partial cost
+ partial_cost += get_item_bidder_cost(item_idx, bidder_idx);
+
+#ifdef LOG_AUCTION
+ if (is_item_diagonal(item_idx)) {
+ num_diag_assignments++;
+ num_diag_assignments_non_cumulative++;
+ } else {
+ num_normal_assignments++;
+ num_normal_assignments_non_cumulative++;
+ }
+
+ if (k_invalid_index != old_item_owner) {
+ if (is_bidder_diagonal(bidder_idx) and is_bidder_diagonal(old_item_owner)) {
+ num_diag_stole_from_diag++;
+ }
+ }
+#endif
+
+ //sanity_check();
+ }
+
+ template<class R, class AO, class PC>
+ typename AuctionRunnerJac<R, AO, PC>::Real
+ AuctionRunnerJac<R, AO, PC>::get_item_bidder_cost(const size_t item_idx, const size_t bidder_idx) const
+ {
+ return std::pow(dist_lp(bidders[bidder_idx], items[item_idx], internal_p, dimension),
+ wasserstein_power);
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::assign_to_best_bidder(IdxType item_idx) {
+ assert(item_idx >= 0 and item_idx < static_cast<IdxType>(num_items));
+ assert(bid_table[item_idx].first != k_invalid_index);
+ IdxValPairR best_bid{bid_table[item_idx]};
+ assign_item_to_bidder(item_idx, best_bid.first);
+ oracle.set_price(item_idx, best_bid.second);
+#ifdef LOG_AUCTION
+
+ if (is_step_parallel) {
+ num_parallel_assignments++;
+ }
+ num_total_assignments++;
+
+ price_change_cnt_vec.back()[item_idx]++;
+#endif
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::clear_bid_table() {
+ auto iter = items_with_bids.begin();
+ while (iter != items_with_bids.end()) {
+ auto item_with_bid_idx = *iter;
+ bid_table[item_with_bid_idx].first = k_invalid_index;
+ bid_table[item_with_bid_idx].second = k_lowest_bid_value;
+ iter = items_with_bids.erase(iter);
+ }
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::submit_bid(IdxType bidder_idx, const IdxValPairR &bid) {
+ IdxType item_idx = bid.first;
+ Real bid_value = bid.second;
+ assert(item_idx >= 0);
+ if (bid_table[item_idx].second < bid_value) {
+ bid_table[item_idx].first = bidder_idx;
+ bid_table[item_idx].second = bid_value;
+ }
+ items_with_bids.insert(item_idx);
+
+#ifdef LOG_AUCTION
+
+ num_total_bids++;
+
+
+ if (is_bidder_diagonal(bidder_idx)) {
+ num_diag_bids_submitted++;
+ } else {
+ num_normal_bids_submitted++;
+ }
+#endif
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::print_debug() {
+#ifdef DEBUG_AUCTION
+ sanity_check();
+ std::cout << "**********************" << std::endl;
+ std::cout << "Current assignment:" << std::endl;
+ for(size_t idx = 0; idx < bidders_to_items.size(); ++idx) {
+ std::cout << idx << " <--> " << bidders_to_items[idx] << std::endl;
+ }
+ std::cout << "Weights: " << std::endl;
+ //for(size_t i = 0; i < num_bidders; ++i) {
+ //for(size_t j = 0; j < num_items; ++j) {
+ //std::cout << oracle.weight_matrix[i][j] << " ";
+ //}
+ //std::cout << std::endl;
+ //}
+ std::cout << "Prices: " << std::endl;
+ for(const auto price : oracle.get_prices()) {
+ std::cout << price << std::endl;
+ }
+ //std::cout << "Value matrix: " << std::endl;
+ //for(size_t i = 0; i < num_bidders; ++i) {
+ //for(size_t j = 0; j < num_items; ++j) {
+ //std::cout << oracle.weight_matrix[i][j] - oracle.prices[j] << " ";
+ //}
+ //std::cout << std::endl;
+ //}
+ std::cout << "**********************" << std::endl;
+#endif
+ }
+
+ template<class R, class AO, class PC>
+ typename AuctionRunnerJac<R, AO, PC>::Real
+ AuctionRunnerJac<R, AO, PC>::get_relative_error(const bool debug_output) const
+ {
+ if (partial_cost == 0.0 and unassigned_bidders.empty())
+ return 0.0;
+ Real result;
+#ifndef WASSERSTEIN_PURE_GEOM
+ Real gamma = get_gamma();
+#else
+ Real gamma = 0.0;
+#endif
+ // cost minus n epsilon
+ Real reduced_cost = partial_cost - num_bidders * get_epsilon();
+ if (reduced_cost < 0) {
+#ifdef LOG_AUCTION
+ if (debug_output) {
+ console_logger->info("Epsilon too large, reduced_cost = {0}, gamma = {1}", reduced_cost, gamma);
+ }
+#endif
+ result = k_max_relative_error;
+ } else {
+ Real denominator = std::pow(reduced_cost, 1.0 / wasserstein_power) - gamma;
+ if (denominator <= 0) {
+#ifdef LOG_AUCTION
+ if (debug_output) {
+ console_logger->info("Epsilon too large, reduced_cost = {0}, denominator = {1}, gamma = {2}",
+ reduced_cost, denominator, gamma);
+ }
+#endif
+ result = k_max_relative_error;
+ } else {
+ Real numerator = 2 * gamma +
+ std::pow(partial_cost, 1.0 / wasserstein_power) -
+ std::pow(reduced_cost, 1.0 / wasserstein_power);
+
+ result = numerator / denominator;
+#ifdef LOG_AUCTION
+ if (debug_output) {
+ console_logger->info(
+ "Reduced_cost = {0}, denominator = {1}, numerator {2}, error = {3}, gamma = {4}",
+ reduced_cost,
+ denominator,
+ numerator,
+ result,
+ gamma);
+ }
+#endif
+ }
+ }
+ return result;
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::flush_assignment() {
+ for (auto &b2i : bidders_to_items) {
+ b2i = k_invalid_index;
+ }
+ for (auto &i2b : items_to_bidders) {
+ i2b = k_invalid_index;
+ }
+
+ // all bidders and items become unassigned
+ for (size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ unassigned_bidders.insert(bidder_idx);
+ }
+
+#ifdef ORDERED_BY_PERSISTENCE
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ if (is_bidder_normal(bidder_idx)) {
+ unassigned_normal_bidders_by_persistence.insert(
+ std::make_pair(bidders[bidder_idx].persistence_lp(1.0), bidder_idx));
+ }
+ }
+#endif
+ oracle.adjust_prices();
+
+ partial_cost = 0.0;
+
+
+#ifndef WASSERSTEIN_PURE_GEOM
+ for (size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ if (is_bidder_normal(bidder_idx)) {
+ unassigned_normal_bidders.insert(bidder_idx);
+ } else {
+ unassigned_diag_bidders.insert(bidder_idx);
+ }
+ }
+
+ unassigned_bidders_persistence = total_bidders_persistence;
+ unassigned_items_persistence = total_items_persistence;
+
+#ifdef LOG_AUCTION
+
+ price_change_cnt_vec.push_back(std::vector<size_t>(num_items, 0));
+
+ never_assigned_bidders = unassigned_bidders;
+
+ for (size_t item_idx = 0; item_idx < items.size(); ++item_idx) {
+ unassigned_items.insert(item_idx);
+ if (is_item_normal(item_idx)) {
+ unassigned_normal_items.insert(item_idx);
+ } else {
+ unassigned_diag_items.insert(item_idx);
+ }
+ }
+
+ num_diag_bids_submitted = 0;
+ num_normal_bids_submitted = 0;
+ num_diag_assignments = 0;
+ num_normal_assignments = 0;
+
+ all_assigned_round = 0;
+ all_assigned_round_found = false;
+ num_rounds_non_cumulative = 0;
+#endif
+#endif
+
+ } // flush_assignment
+
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::set_epsilon(Real new_val) {
+ assert(new_val > 0.0);
+ epsilon = new_val;
+ oracle.set_epsilon(new_val);
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::run_auction_phases(const int max_num_phases, const Real _initial_epsilon) {
+ set_epsilon(_initial_epsilon);
+ assert(oracle.get_epsilon() > 0);
+ for (int phase_num = 0; phase_num < max_num_phases; ++phase_num) {
+ flush_assignment();
+ run_auction_phase();
+
+#ifdef LOG_AUCTION
+ console_logger->info(
+ "Phase {0} done, current_result = {1}, eps = {2}, error = {7}, num_rounds = {3}, num_assignments = {4}, num_bids_submitted = {5}, # unassigned = {6}",
+ num_phase,
+ partial_cost,
+ get_epsilon(),
+ format_int<>(num_rounds),
+ format_int<>(num_normal_assignments + num_diag_assignments),
+ format_int<>(num_normal_bids_submitted + num_diag_bids_submitted),
+ unassigned_bidders.size(),
+ get_relative_error(num_phase == 1)
+ );
+
+// console_logger->info("num_rounds (non-cumulative)= {0}, num_diag_assignments = {1}, num_normal_assignments = {2}, num_diag_bids_submitted = {3}, num_normal_bids_submitted = {4}",
+// format_int<>(num_rounds_non_cumulative),
+// format_int<>(num_diag_assignments),
+// format_int<>(num_normal_assignments),
+// format_int<>(num_diag_bids_submitted),
+// format_int<>(num_normal_bids_submitted)
+// );
+
+ console_logger->info(
+ "num_parallel_bids / num_total_bids = {0} / {1} = {2}, num_parallel_assignments / num_total_aassignments = {3} / {4} = {5}",
+ format_int<>(num_parallel_bids),
+ format_int<>(num_total_bids),
+ static_cast<double>(num_parallel_bids) / static_cast<double>(num_total_bids),
+ format_int<>(num_parallel_assignments),
+ format_int<>(num_total_assignments),
+ static_cast<double>(num_parallel_assignments) / static_cast<double>(num_total_assignments)
+ );
+
+ console_logger->info(
+ "num_parallel_diag_bids / num_total_diag_bids = {0} / {1} = {2}, num_parallel_normal_bids / num_total_normal_bids = {3} / {4} = {5}",
+ format_int<>(num_parallel_diag_bids),
+ format_int<>(num_total_diag_bids),
+ static_cast<double>(num_parallel_diag_bids) / static_cast<double>(num_total_diag_bids),
+ format_int<>(num_parallel_normal_bids),
+ format_int<>(num_total_normal_bids),
+ static_cast<double>(num_parallel_normal_bids) / static_cast<double>(num_total_normal_bids)
+ );
+
+// console_logger->info("num_rounds before all biders assigned = {0}, num_rounds (non-cumulative)= {1}, fraction = {2}",
+// format_int<>(all_assigned_round),
+// format_int<>(num_rounds_non_cumulative),
+// static_cast<double>(all_assigned_round) / static_cast<double>(num_rounds_non_cumulative)
+// );
+
+ for (size_t item_idx = 0; item_idx < num_items; ++item_idx) {
+ price_stat_logger->info("{0} {1} {2} {3} {4}",
+ phase_num,
+ item_idx,
+ items[item_idx][0],
+ items[item_idx][1],
+ price_change_cnt_vec.back()[item_idx]
+ );
+ }
+#endif
+
+
+ if (is_done())
+ break;
+ else
+ decrease_epsilon();
+
+ }
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::decrease_epsilon() {
+ set_epsilon(get_epsilon() / epsilon_common_ratio);
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::run_auction()
+ {
+ if (num_bidders == 1) {
+ assign_item_to_bidder(0, 0);
+ wasserstein_cost = get_item_bidder_cost(0,0);
+ is_distance_computed = true;
+ return;
+ }
+ R init_eps = (initial_epsilon > 0.0) ? initial_epsilon : oracle.max_val_ / 4.0;
+ run_auction_phases(max_num_phases, init_eps);
+ is_distance_computed = true;
+ wasserstein_cost = partial_cost;
+ if (not is_done()) {
+#ifndef FOR_R_TDA
+ std::cerr << "Maximum iteration number exceeded, exiting. Current result is: ";
+ std::cerr << get_wasserstein_distance() << std::endl;
+#endif
+ throw std::runtime_error("Maximum iteration number exceeded");
+ }
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::add_unassigned_bidder(const size_t bidder_idx)
+ {
+ unassigned_bidders.insert(bidder_idx);
+
+#ifndef WASSERSTEIN_PURE_GEOM
+ const auto &bidder = bidders[bidder_idx];
+ unassigned_bidders_persistence += get_cost_to_diagonal(bidder);
+
+ if (is_bidder_diagonal(bidder_idx)) {
+ unassigned_diag_bidders.insert(bidder_idx);
+ } else {
+ unassigned_normal_bidders.insert(bidder_idx);
+ }
+#ifdef ORDERED_BY_PERSISTENCE
+ if (is_bidder_normal(bidder_idx)) {
+ unassigned_normal_bidders_by_persistence.insert(std::make_pair(bidder.persistence_lp(1.0), bidder_idx));
+ }
+#endif
+
+#endif
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::remove_unassigned_bidder(const size_t bidder_idx)
+ {
+ unassigned_bidders.erase(bidder_idx);
+#ifndef WASSERSTEIN_PURE_GEOM
+ const auto &bidder = bidders[bidder_idx];
+ unassigned_bidders_persistence -= get_cost_to_diagonal(bidder);
+
+#ifdef ORDERED_BY_PERSISTENCE
+ if (is_bidder_normal(bidder_idx)) {
+ unassigned_normal_bidders_by_persistence.erase(std::make_pair(bidder.persistence_lp(1.0), bidder_idx));
+ }
+#endif
+
+ if (is_bidder_diagonal(bidder_idx)) {
+ unassigned_diag_bidders.erase(bidder_idx);
+ } else {
+ unassigned_normal_bidders.erase(bidder_idx);
+ }
+
+
+#ifdef LOG_AUCTION
+ never_assigned_bidders.erase(bidder_idx);
+ if (never_assigned_bidders.empty() and not all_assigned_round_found) {
+ all_assigned_round = num_rounds_non_cumulative;
+ all_assigned_round_found = true;
+ }
+#endif
+#endif
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::remove_unassigned_item(const size_t item_idx) {
+#ifndef WASSERSTEIN_PURE_GEOM
+ unassigned_items_persistence -= get_cost_to_diagonal(items[item_idx]);
+
+#ifdef LOG_AUCTION
+ unassigned_items.erase(item_idx);
+
+ if (is_item_normal(item_idx)) {
+ unassigned_normal_items.erase(item_idx);
+ } else {
+ unassigned_diag_items.erase(item_idx);
+ }
+#endif
+#endif
+ }
+
+ template<class R, class AO, class PC>
+ template<class Range>
+ void AuctionRunnerJac<R, AO, PC>::run_bidding_step(const Range &active_bidders)
+ {
+#ifdef LOG_AUCTION
+ is_step_parallel = false;
+ size_t diag_bids_submitted = 0;
+ size_t normal_bids_submitted = 0;
+#endif
+
+ clear_bid_table();
+ size_t bids_submitted = 0;
+ for (const auto bidder_idx : active_bidders) {
+
+ ++bids_submitted;
+
+ submit_bid(bidder_idx, oracle.get_optimal_bid(bidder_idx));
+
+#ifdef LOG_AUCTION
+ if (is_bidder_diagonal(bidder_idx)) {
+ diag_bids_submitted++;
+ } else {
+ normal_bids_submitted++;
+ }
+
+ if (bids_submitted >= parallel_threshold) {
+ is_step_parallel = true;
+ }
+
+ if (bids_submitted >= max_bids_per_round) {
+ break;
+ }
+ if (diag_first and not unassigned_diag_bidders.empty() and
+ diag_bids_submitted >= oracle.get_heap_top_size()) {
+ continue;
+ }
+#endif
+ }
+
+#ifdef LOG_AUCTION
+ num_total_diag_bids += diag_bids_submitted;
+ num_total_normal_bids += normal_bids_submitted;
+ if (is_step_parallel) {
+ num_parallel_bids += bids_submitted;
+ num_parallel_diag_bids += diag_bids_submitted;
+ num_parallel_normal_bids += normal_bids_submitted;
+ }
+#endif
+ }
+
+ template<class R, class AO, class PC>
+ bool AuctionRunnerJac<R, AO, PC>::is_done() const
+ {
+ return get_relative_error() <= delta;
+ }
+
+ template<class R, class AO, class PC>
+ bool AuctionRunnerJac<R, AO, PC>::continue_auction_phase() const
+ {
+#ifdef WASSERSTEIN_PURE_GEOM
+ return not unassigned_bidders.empty();
+#else
+ return not unassigned_bidders.empty() and not is_done();
+#endif
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::run_auction_phase()
+ {
+ num_phase++;
+ //console_logger->debug("Entered run_auction_phase");
+
+ do {
+ num_rounds++;
+#ifdef LOG_AUCTION
+ num_diag_stole_from_diag = 0;
+ num_normal_assignments_non_cumulative = 0;
+ num_diag_assignments_non_cumulative = 0;
+ num_rounds_non_cumulative++;
+#endif
+
+ // bidding
+#ifdef ORDERED_BY_PERSISTENCE
+ if (not unassigned_diag_bidders.empty()) {
+ run_bidding_step(unassigned_diag_bidders);
+ } else {
+ std::vector<size_t> active_bidders;
+ active_bidders.reserve(batch_size);
+ for (auto iter = unassigned_normal_bidders_by_persistence.begin(); iter != unassigned_normal_bidders_by_persistence.end(); ++iter) {
+ active_bidders.push_back(iter->second);
+ if (active_bidders.size() >= batch_size) {
+ break;
+ }
+ }
+ run_bidding_step(active_bidders);
+ }
+#elif defined WASSERSTEIN_PURE_GEOM
+ run_bidding_step(unassigned_bidders);
+#else
+ if (diag_first and not unassigned_diag_bidders.empty()) {
+ run_bidding_step(unassigned_diag_bidders);
+ } else {
+ run_bidding_step(unassigned_bidders);
+ }
+#endif
+
+ // assignment
+ for (auto item_idx : items_with_bids) {
+ assign_to_best_bidder(item_idx);
+ }
+#ifdef LOG_AUCTION
+ plot_logger->info("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14}",
+ num_phase,
+ num_rounds,
+ unassigned_bidders.size(),
+ get_gamma(),
+ partial_cost,
+ oracle.get_epsilon(),
+ unassigned_normal_bidders.size(),
+ unassigned_diag_bidders.size(),
+ unassigned_normal_items.size(),
+ unassigned_diag_items.size(),
+ num_normal_assignments_non_cumulative,
+ num_diag_assignments_non_cumulative,
+ oracle.get_heap_top_size(),
+ get_relative_error(false),
+ num_diag_stole_from_diag
+ );
+#endif
+ //sanity_check();
+ } while (continue_auction_phase());
+ }
+
+ template<class R, class AO, class PC>
+ typename AuctionRunnerJac<R, AO, PC>::Real
+ AuctionRunnerJac<R, AO, PC>::get_wasserstein_distance()
+ {
+ assert(is_distance_computed);
+ return std::pow(wasserstein_cost, 1.0 / wasserstein_power);
+ }
+
+ template<class R, class AO, class PC>
+ typename AuctionRunnerJac<R, AO, PC>::Real
+ AuctionRunnerJac<R, AO, PC>::get_wasserstein_cost()
+ {
+ assert(is_distance_computed);
+ return wasserstein_cost;
+ }
+
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::sanity_check()
+ {
+#ifdef DEBUG_AUCTION
+ if (bidders_to_items.size() != num_bidders) {
+ std::cerr << "Wrong size of bidders_to_items, must be " << num_bidders << ", is " << bidders_to_items.size() << std::endl;
+ throw "Wrong size of bidders_to_items";
+ }
+
+ if (items_to_bidders.size() != num_bidders) {
+ std::cerr << "Wrong size of items_to_bidders, must be " << num_bidders << ", is " << items_to_bidders.size() << std::endl;
+ throw "Wrong size of items_to_bidders";
+ }
+
+ for(size_t bidder_idx = 0; bidder_idx < num_bidders; ++bidder_idx) {
+ if ( bidders_to_items[bidder_idx] >= 0) {
+
+ if ( std::count(bidders_to_items.begin(),
+ bidders_to_items.end(),
+ bidders_to_items[bidder_idx]) > 1 ) {
+ std::cerr << "Good " << bidders_to_items[bidder_idx];
+ std::cerr << " appears in bidders_to_items more than once" << std::endl;
+ throw "Duplicate in bidders_to_items";
+ }
+
+ if (items_to_bidders.at(bidders_to_items[bidder_idx]) != static_cast<int>(bidder_idx)) {
+ std::cerr << "Inconsitency: bidder_idx = " << bidder_idx;
+ std::cerr << ", item_idx in bidders_to_items = ";
+ std::cerr << bidders_to_items[bidder_idx];
+ std::cerr << ", bidder_idx in items_to_bidders = ";
+ std::cerr << items_to_bidders[bidders_to_items[bidder_idx]] << std::endl;
+ throw "inconsistent mapping";
+ }
+ }
+ }
+
+ for(IdxType item_idx = 0; item_idx < static_cast<IdxType>(num_bidders); ++item_idx) {
+ if ( items_to_bidders[item_idx] >= 0) {
+
+ // check for uniqueness
+ if ( std::count(items_to_bidders.begin(),
+ items_to_bidders.end(),
+ items_to_bidders[item_idx]) > 1 ) {
+ std::cerr << "Bidder " << items_to_bidders[item_idx];
+ std::cerr << " appears in items_to_bidders more than once" << std::endl;
+ throw "Duplicate in items_to_bidders";
+ }
+ // check for consistency
+ if (bidders_to_items.at(items_to_bidders[item_idx]) != static_cast<int>(item_idx)) {
+ std::cerr << "Inconsitency: item_idx = " << item_idx;
+ std::cerr << ", bidder_idx in items_to_bidders = ";
+ std::cerr << items_to_bidders[item_idx];
+ std::cerr << ", item_idx in bidders_to_items= ";
+ std::cerr << bidders_to_items[items_to_bidders[item_idx]] << std::endl;
+ throw "inconsistent mapping";
+ }
+ }
+ }
+#endif
+ }
+
+ template<class R, class AO, class PC>
+ void AuctionRunnerJac<R, AO, PC>::print_matching() {
+#ifdef DEBUG_AUCTION
+ sanity_check();
+ for(size_t bidder_idx = 0; bidder_idx < bidders_to_items.size(); ++bidder_idx) {
+ if (bidders_to_items[bidder_idx] >= 0) {
+ auto pA = bidders[bidder_idx];
+ auto pB = items[bidders_to_items[bidder_idx]];
+ std::cout << pA << " <-> " << pB << "+" << pow(dist_lp(pA, pB, internal_p, dimension), wasserstein_power) << std::endl;
+ } else {
+ assert(false);
+ }
+ }
+#endif
+ }
+
+} // ws
+} // hera
+
+#endif
diff --git a/wasserstein/include/basic_defs_ws.h b/wasserstein/include/basic_defs_ws.h
new file mode 100644
index 0000000..bdcfd75
--- /dev/null
+++ b/wasserstein/include/basic_defs_ws.h
@@ -0,0 +1,321 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef BASIC_DEFS_WS_H
+#define BASIC_DEFS_WS_H
+
+#include <vector>
+#include <math.h>
+#include <cstddef>
+#include <unordered_map>
+#include <unordered_set>
+#include <string>
+#include <iomanip>
+#include <locale>
+#include <cassert>
+#include <limits>
+#include <ostream>
+#include <typeinfo>
+
+#ifdef _WIN32
+#include <ciso646>
+#endif
+
+#include "hera_infinity.h"
+#include "dnn/geometry/euclidean-dynamic.h"
+#include "def_debug_ws.h"
+
+#define MIN_VALID_ID 10
+
+namespace hera
+{
+
+//template<class Real = double>
+//inline bool is_infinity(const Real& x)
+//{
+// return x == Real(-1);
+//};
+//
+//template<class Real = double>
+//inline Real get_infinity()
+//{
+// return Real( -1 );
+//}
+
+template<class Real = double>
+inline bool is_p_valid_norm(const Real& p)
+{
+ return is_infinity<Real>(p) or p >= Real(1);
+}
+
+template<class Real = double>
+struct AuctionParams
+{
+ Real wasserstein_power { 1.0 };
+ Real delta { 0.01 }; // relative error
+ Real internal_p { get_infinity<Real>() };
+ Real initial_epsilon { 0.0 }; // 0.0 means maxVal / 4.0
+ Real epsilon_common_ratio { 5.0 };
+ Real gamma_threshold { 0.0 }; // for experiments, not in use now
+ int max_num_phases { std::numeric_limits<decltype(max_num_phases)>::max() };
+ int max_bids_per_round { 1 }; // imitate Gauss-Seidel is default behaviour
+ unsigned int dim { 2 }; // for pure geometric version only; ignored in persistence diagrams
+ Real final_relative_error; // out parameter - after auction terminates, contains the real relative error
+ bool tolerate_max_iter_exceeded { false }; // whether auction should throw an exception on max. iterations exceeded
+};
+
+namespace ws
+{
+
+ using IdxType = int;
+
+ constexpr size_t k_invalid_index = std::numeric_limits<IdxType>::max();
+
+ template<class Real = double>
+ using IdxValPair = std::pair<IdxType, Real>;
+
+ template<class R>
+ inline std::ostream& operator<<(std::ostream& output, const IdxValPair<R> p)
+ {
+ output << "(" << p.first << ", " << p.second << ")";
+ return output;
+ }
+
+ enum class OwnerType { k_none, k_normal, k_diagonal };
+
+ inline std::ostream& operator<<(std::ostream& s, const OwnerType t)
+ {
+ switch(t)
+ {
+ case OwnerType::k_none : s << "NONE"; break;
+ case OwnerType::k_normal: s << "NORMAL"; break;
+ case OwnerType::k_diagonal: s << "DIAGONAL"; break;
+ }
+ return s;
+ }
+
+ template<class Real = double>
+ struct Point {
+ Real x, y;
+ bool operator==(const Point& other) const;
+ bool operator!=(const Point& other) const;
+ Point(Real _x, Real _y) : x(_x), y(_y) {}
+ Point() : x(0.0), y(0.0) {}
+ };
+
+#ifndef FOR_R_TDA
+ template<class Real = double>
+ std::ostream& operator<<(std::ostream& output, const Point<Real> p);
+#endif
+
+ template <class T>
+ inline void hash_combine(std::size_t & seed, const T & v)
+ {
+ std::hash<T> hasher;
+ seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ }
+
+ template<class Real_ = double>
+ struct DiagramPoint
+ {
+ using Real = Real_;
+ // data members
+ // Points above the diagonal have type NORMAL
+ // Projections onto the diagonal have type DIAG
+ // for DIAG points only x-coordinate is relevant
+ enum Type { NORMAL, DIAG};
+ Real x, y;
+ Type type;
+ // methods
+ DiagramPoint(Real xx, Real yy, Type ttype);
+ bool is_diagonal() const { return type == DIAG; }
+ bool is_normal() const { return type == NORMAL; }
+ Real getRealX() const; // return the x-coord
+ Real getRealY() const; // return the y-coord
+ Real persistence_lp(const Real p) const;
+ struct LexicographicCmp
+ {
+ bool operator()(const DiagramPoint& p1, const DiagramPoint& p2) const
+ { return p1.type < p2.type || (p1.type == p2.type && (p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y))); }
+ };
+
+ const Real& operator[](const int idx) const
+ {
+ switch(idx)
+ {
+ case 0 : return x;
+ break;
+ case 1 : return y;
+ break;
+ default: throw std::out_of_range("DiagramPoint has dimension 2");
+ }
+ }
+
+ Real& operator[](const int idx)
+ {
+ switch(idx)
+ {
+ case 0 : return x;
+ break;
+ case 1 : return y;
+ break;
+ default: throw std::out_of_range("DiagramPoint has dimension 2");
+ }
+ }
+
+ };
+
+
+ template<class Real>
+ struct DiagramPointHash {
+ size_t operator()(const DiagramPoint<Real> &p) const
+ {
+ std::size_t seed = 0;
+ hash_combine(seed, std::hash<Real>(p.x));
+ hash_combine(seed, std::hash<Real>(p.y));
+ hash_combine(seed, std::hash<bool>(p.is_diagonal()));
+ return seed;
+ }
+ };
+
+
+#ifndef FOR_R_TDA
+ template <class Real = double>
+ inline std::ostream& operator<<(std::ostream& output, const DiagramPoint<Real> p);
+#endif
+
+ template<class Real, class Pt>
+ struct DistImpl
+ {
+ Real operator()(const Pt& a, const Pt& b, const Real p, const int dim)
+ {
+ Real result = 0.0;
+ if (hera::is_infinity(p)) {
+ for(int d = 0; d < dim; ++d) {
+ result = std::max(result, std::fabs(a[d] - b[d]));
+ }
+ } else if (p == 1.0) {
+ for(int d = 0; d < dim; ++d) {
+ result += std::fabs(a[d] - b[d]);
+ }
+ } else {
+ assert(p > 1.0);
+ for(int d = 0; d < dim; ++d) {
+ result += std::pow(std::fabs(a[d] - b[d]), p);
+ }
+ result = std::pow(result, 1.0 / p);
+ }
+ return result;
+ }
+ };
+
+ template<class Real>
+ struct DistImpl<Real, DiagramPoint<Real>>
+ {
+ Real operator()(const DiagramPoint<Real>& a, const DiagramPoint<Real>& b, const Real p, const int dim)
+ {
+ Real result = 0.0;
+ if ( a.is_diagonal() and b.is_diagonal()) {
+ return result;
+ } else if (hera::is_infinity(p)) {
+ result = std::max(std::fabs(a.getRealX() - b.getRealX()), std::fabs(a.getRealY() - b.getRealY()));
+ } else if (p == 1.0) {
+ result = std::fabs(a.getRealX() - b.getRealX()) + std::fabs(a.getRealY() - b.getRealY());
+ } else {
+ assert(p > 1.0);
+ result = std::pow(std::pow(std::fabs(a.getRealX() - b.getRealX()), p) + std::pow(std::fabs(a.getRealY() - b.getRealY()), p), 1.0 / p);
+ }
+ return result;
+ }
+ };
+
+ template<class R, class Pt>
+ inline R dist_lp(const Pt& a, const Pt& b, const R p, const int dim)
+ {
+ return DistImpl<R, Pt>()(a, b, p, dim);
+ }
+
+ // TODO
+ template<class Real, typename DiagPointContainer>
+ inline double getFurthestDistance3Approx(DiagPointContainer& A, DiagPointContainer& B, const Real p)
+ {
+ int dim = 2;
+ Real result { 0.0 };
+ DiagramPoint<Real> begA = *(A.begin());
+ DiagramPoint<Real> optB = *(B.begin());
+ for(const auto& pointB : B) {
+ if (dist_lp(begA, pointB, p, dim) > result) {
+ result = dist_lp(begA, pointB, p, dim);
+ optB = pointB;
+ }
+ }
+ for(const auto& pointA : A) {
+ if (dist_lp(pointA, optB, p, dim) > result) {
+ result = dist_lp(pointA, optB, p, dim);
+ }
+ }
+ return result;
+ }
+
+ template<class Real>
+ inline Real getFurthestDistance3Approx_pg(const hera::ws::dnn::DynamicPointVector<Real>& A, const hera::ws::dnn::DynamicPointVector<Real>& B, const Real p, const int dim)
+ {
+ Real result { 0.0 };
+ int opt_b_idx = 0;
+ for(size_t b_idx = 0; b_idx < B.size(); ++b_idx) {
+ if (dist_lp(A[0], B[b_idx], p, dim) > result) {
+ result = dist_lp(A[0], B[b_idx], p, dim);
+ opt_b_idx = b_idx;
+ }
+ }
+
+ for(size_t a_idx = 0; a_idx < A.size(); ++a_idx) {
+ result = std::max(result, dist_lp(A[a_idx], B[opt_b_idx], p, dim));
+ }
+
+ return result;
+ }
+
+
+ template<class Container>
+ inline std::string format_container_to_log(const Container& cont);
+
+ template<class Real, class IndexContainer>
+ inline std::string format_point_set_to_log(const IndexContainer& indices, const std::vector<DiagramPoint<Real>>& points);
+
+ template<class T>
+ inline std::string format_int(T i);
+
+} // ws
+} // hera
+
+
+
+#include "basic_defs_ws.hpp"
+
+
+#endif
diff --git a/wasserstein/include/basic_defs_ws.hpp b/wasserstein/include/basic_defs_ws.hpp
new file mode 100644
index 0000000..a1153af
--- /dev/null
+++ b/wasserstein/include/basic_defs_ws.hpp
@@ -0,0 +1,220 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+Copyright (c) 2018, G. Spreemann
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+*/
+
+#pragma once
+
+#include <algorithm>
+#include <cfloat>
+#include <set>
+#include <algorithm>
+#include <istream>
+#include <cstdint>
+#include "basic_defs_ws.h"
+
+#ifndef FOR_R_TDA
+#include <iostream>
+#endif
+
+#include <sstream>
+
+namespace hera {
+static const int64_t DIPHA_MAGIC = 8067171840;
+static const int64_t DIPHA_PERSISTENCE_DIAGRAM = 2;
+
+namespace ws {
+// Point
+
+template <class Real>
+bool Point<Real>::operator==(const Point<Real>& other) const
+{
+ return ((this->x == other.x) and (this->y == other.y));
+}
+
+template <class Real>
+bool Point<Real>::operator!=(const Point<Real>& other) const
+{
+ return !(*this == other);
+}
+
+
+#ifndef FOR_R_TDA
+template <class Real>
+inline std::ostream& operator<<(std::ostream& output, const Point<Real> p)
+{
+ output << "(" << p.x << ", " << p.y << ")";
+ return output;
+}
+#endif
+
+template <class Real>
+inline Real sqr_dist(const Point<Real>& a, const Point<Real>& b)
+{
+ return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
+}
+
+template <class Real>
+inline Real dist(const Point<Real>& a, const Point<Real>& b)
+{
+ return sqrt(sqr_dist(a, b));
+}
+
+
+template <class Real>
+inline Real DiagramPoint<Real>::persistence_lp(const Real p) const
+{
+ if (is_diagonal())
+ return 0.0;
+ else {
+ Real u { (getRealY() + getRealX())/2 };
+ int dim = 2;
+ DiagramPoint<Real> a_proj(u, u, DiagramPoint<Real>::DIAG);
+ return dist_lp(*this, a_proj, p, dim);
+ }
+}
+
+
+#ifndef FOR_R_TDA
+template <class Real>
+inline std::ostream& operator<<(std::ostream& output, const DiagramPoint<Real> p)
+{
+ if ( p.type == DiagramPoint<Real>::DIAG ) {
+ output << "(" << p.x << ", " << p.y << ", " << 0.5 * (p.x + p.y) << " DIAG )";
+ } else {
+ output << "(" << p.x << ", " << p.y << ", " << " NORMAL)";
+ }
+ return output;
+}
+#endif
+
+template <class Real>
+DiagramPoint<Real>::DiagramPoint(Real xx, Real yy, Type ttype) :
+ x(xx),
+ y(yy),
+ type(ttype)
+{
+ //if ( yy < xx )
+ //throw "Point is below the diagonal";
+ //if ( yy == xx and ttype != DiagramPoint<Real>::DIAG)
+ //throw "Point on the main diagonal must have DIAG type";
+}
+
+template <class Real>
+Real DiagramPoint<Real>::getRealX() const
+{
+ if (is_normal())
+ return x;
+ else
+ return Real(0.5) * (x + y);
+}
+
+template <class Real>
+Real DiagramPoint<Real>::getRealY() const
+{
+ if (is_normal())
+ return y;
+ else
+ return Real(0.5) * (x + y);
+}
+
+template<class Container>
+inline std::string format_container_to_log(const Container& cont)
+{
+ std::stringstream result;
+ result << "[";
+ for(auto iter = cont.begin(); iter != cont.end(); ++iter) {
+ result << *iter;
+ if (std::next(iter) != cont.end()) {
+ result << ", ";
+ }
+ }
+ result << "]";
+ return result.str();
+}
+
+template<class Container>
+inline std::string format_pair_container_to_log(const Container& cont)
+{
+ std::stringstream result;
+ result << "[";
+ for(auto iter = cont.begin(); iter != cont.end(); ++iter) {
+ result << "(" << iter->first << ", " << iter->second << ")";
+ if (std::next(iter) != cont.end()) {
+ result << ", ";
+ }
+ }
+ result << "]";
+ return result.str();
+}
+
+
+template<class Real, class IndexContainer>
+inline std::string format_point_set_to_log(const IndexContainer& indices,
+ const std::vector<DiagramPoint<Real>>& points)
+{
+ std::stringstream result;
+ result << "[";
+ for(auto iter = indices.begin(); iter != indices.end(); ++iter) {
+ DiagramPoint<Real> p = points[*iter];
+ result << "(" << p.getRealX() << ", " << p.getRealY() << ")";
+ if (std::next(iter) != indices.end())
+ result << ", ";
+ }
+ result << "]";
+ return result.str();
+}
+
+template<class T>
+inline std::string format_int(T i)
+{
+ std::stringstream ss;
+ ss.imbue(std::locale(""));
+ ss << std::fixed << i;
+ return ss.str();
+}
+
+
+} // end of namespace ws
+
+
+template <typename T> inline void reverse_endianness(T & x)
+{
+ uint8_t * p = reinterpret_cast<uint8_t *>(&x);
+ std::reverse(p, p + sizeof(T));
+}
+
+template <typename T> inline T read_le(std::istream & s)
+{
+ T result;
+ s.read(reinterpret_cast<char *>(&result), sizeof(T));
+ #ifdef BIGENDIAN
+ reverse_endianness(result);
+ #endif
+ return result;
+}
+
+} // hera
diff --git a/wasserstein/include/def_debug_ws.h b/wasserstein/include/def_debug_ws.h
new file mode 100644
index 0000000..791ce1d
--- /dev/null
+++ b/wasserstein/include/def_debug_ws.h
@@ -0,0 +1,44 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef DEF_DEBUG_WS_H
+#define DEF_DEBUG_WS_H
+
+//#define DEBUG_BOUND_MATCH
+//#define DEBUG_NEIGHBOUR_ORACLE
+//#define DEBUG_MATCHING
+//#define DEBUG_AUCTION
+// This symbol should be defined only in the version
+// for R package TDA, to comply with some CRAN rules
+// like no usage of cout, cerr, cin, exit, etc.
+//#define FOR_R_TDA
+//
+//#define DEBUG_KDTREE_RESTR_ORACLE
+//#define DEBUG_STUPID_SPARSE_RESTR_ORACLE
+//#define DEBUG_FR_AUCTION
+
+#endif
diff --git a/wasserstein/include/diagonal_heap.h b/wasserstein/include/diagonal_heap.h
new file mode 100644
index 0000000..3b3c8bc
--- /dev/null
+++ b/wasserstein/include/diagonal_heap.h
@@ -0,0 +1,149 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef DIAGONAL_HEAP_H
+#define DIAGONAL_HEAP_H
+
+//#define USE_BOOST_HEAP
+
+#include <map>
+#include <memory>
+#include <set>
+#include <list>
+
+#ifdef USE_BOOST_HEAP
+#include <boost/heap/d_ary_heap.hpp>
+#endif
+
+#include "basic_defs_ws.h"
+
+namespace hera {
+namespace ws {
+
+template <typename T>
+struct CompPairsBySecondLexStruct {
+ bool operator()(const IdxValPair<T>& a, const IdxValPair<T>& b) const
+ {
+ return a.second < b.second or (a.second == b.second and a.first > b.first);
+ }
+};
+
+
+template <typename T>
+struct CompPairsBySecondGreaterStruct {
+ bool operator()(const IdxValPair<T>& a, const IdxValPair<T>& b) const
+ {
+ return a.second > b.second;
+ }
+};
+
+#ifdef USE_BOOST_HEAP
+template <class Real>
+using LossesHeapOld = boost::heap::d_ary_heap<IdxValPair<Real>, boost::heap::arity<2>, boost::heap::mutable_<true>, boost::heap::compare<CompPairsBySecondGreaterStruct<Real>>>;
+#else
+template<typename T, class ComparisonStruct>
+class IdxValHeap {
+public:
+ using InternalKeeper = std::set<IdxValPair<T>, ComparisonStruct>;
+ using handle_type = typename InternalKeeper::iterator;
+ using const_handle_type = typename InternalKeeper::const_iterator;
+ // methods
+ handle_type push(const IdxValPair<T>& val)
+ {
+ auto res_pair = _heap.insert(val);
+ assert(res_pair.second);
+ assert(res_pair.first != _heap.end());
+ return res_pair.first;
+ }
+
+ void decrease(handle_type& handle, const IdxValPair<T>& new_val)
+ {
+ _heap.erase(handle);
+ handle = push(new_val);
+ }
+
+ void increase(handle_type& handle, const IdxValPair<T>& new_val)
+ {
+ _heap.erase(handle);
+ handle = push(new_val);
+ }
+
+ size_t size() const
+ {
+ return _heap.size();
+ }
+
+ handle_type ordered_begin()
+ {
+ return _heap.begin();
+ }
+
+ handle_type ordered_end()
+ {
+ return _heap.end();
+ }
+
+ const_handle_type ordered_begin() const
+ {
+ return _heap.cbegin();
+ }
+
+ const_handle_type ordered_end() const
+ {
+ return _heap.cend();
+ }
+
+
+private:
+ std::set<IdxValPair<T>, ComparisonStruct> _heap;
+};
+
+// if we store losses, the minimal value should come first
+template <class Real>
+using LossesHeapOld = IdxValHeap<Real, CompPairsBySecondLexStruct<Real>>;
+#endif
+
+template <class Real>
+inline std::string losses_heap_to_string(const LossesHeapOld<Real>& h)
+{
+ std::stringstream result;
+ result << "[";
+ for(auto iter = h.ordered_begin(); iter != h.ordered_end(); ++iter) {
+ result << *iter;
+ if (std::next(iter) != h.ordered_end()) {
+ result << ", ";
+ }
+ }
+ result << "]";
+ return result.str();
+}
+
+} // ws
+} // hera
+
+#endif // DIAGONAL_HEAP_H
diff --git a/wasserstein/include/diagram_reader.h b/wasserstein/include/diagram_reader.h
new file mode 100644
index 0000000..b52fcbd
--- /dev/null
+++ b/wasserstein/include/diagram_reader.h
@@ -0,0 +1,447 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+Copyright (c) 2018, G. Spreemann
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+*/
+
+#ifndef HERA_DIAGRAM_READER_H
+#define HERA_DIAGRAM_READER_H
+
+#ifndef FOR_R_TDA
+#include <iostream>
+#endif
+
+#include <iomanip>
+#include <locale>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <cctype>
+#include <algorithm>
+#include <map>
+#include <limits>
+
+#include "basic_defs_ws.hpp"
+
+#ifdef WASSERSTEIN_PURE_GEOM
+#include "dnn/geometry/euclidean-dynamic.h"
+#endif
+
+namespace hera {
+
+// cannot choose stod, stof or stold based on RealType,
+// lazy solution: partial specialization
+template<class RealType = double>
+inline RealType parse_real_from_str(const std::string& s);
+
+template <>
+inline double parse_real_from_str<double>(const std::string& s)
+{
+ return std::stod(s);
+}
+
+
+template <>
+inline long double parse_real_from_str<long double>(const std::string& s)
+{
+ return std::stold(s);
+}
+
+
+template <>
+inline float parse_real_from_str<float>(const std::string& s)
+{
+ return std::stof(s);
+}
+
+
+template<class RealType>
+inline RealType parse_real_from_str(const std::string& s)
+{
+ static_assert(sizeof(RealType) != sizeof(RealType), "Must be specialized for each type you want to use, see above");
+}
+
+// fill in result with points from file fname
+// return false if file can't be opened
+// or error occurred while reading
+// decPrecision is the maximal decimal precision in the input,
+// it is zero if all coordinates in the input are integers
+template<class RealType = double, class ContType_ = std::vector<std::pair<RealType, RealType>>>
+inline bool read_diagram_point_set(const char* fname, ContType_& result, int& decPrecision)
+{
+ size_t lineNumber { 0 };
+ result.clear();
+ std::ifstream f(fname);
+ if (!f.good()) {
+#ifndef FOR_R_TDA
+ std::cerr << "Cannot open file " << fname << std::endl;
+#endif
+ return false;
+ }
+ std::locale loc;
+ std::string line;
+ while(std::getline(f, line)) {
+ lineNumber++;
+ // process comments: remove everything after hash
+ auto hashPos = line.find_first_of("#", 0);
+ if( std::string::npos != hashPos) {
+ line = std::string(line.begin(), line.begin() + hashPos);
+ }
+ if (line.empty()) {
+ continue;
+ }
+ // trim whitespaces
+ auto whiteSpaceFront = std::find_if_not(line.begin(),line.end(),isspace);
+ auto whiteSpaceBack = std::find_if_not(line.rbegin(),line.rend(),isspace).base();
+ if (whiteSpaceBack <= whiteSpaceFront) {
+ // line consists of spaces only - move to the next line
+ continue;
+ }
+ line = std::string(whiteSpaceFront,whiteSpaceBack);
+
+ // transform line to lower case
+ // to parse Infinity
+ for(auto& c : line) {
+ c = std::tolower(c, loc);
+ }
+
+ bool fracPart = false;
+ int currDecPrecision = 0;
+ for(auto c : line) {
+ if (c == '.') {
+ fracPart = true;
+ } else if (fracPart) {
+ if (isdigit(c)) {
+ currDecPrecision++;
+ } else {
+ fracPart = false;
+ if (currDecPrecision > decPrecision)
+ decPrecision = currDecPrecision;
+ currDecPrecision = 0;
+ }
+ }
+ }
+
+ RealType x, y;
+ std::string str_x, str_y;
+ std::istringstream iss(line);
+ try {
+ iss >> str_x >> str_y;
+
+ x = parse_real_from_str<RealType>(str_x);
+ y = parse_real_from_str<RealType>(str_y);
+
+ if (x != y) {
+ result.push_back(std::make_pair(x, y));
+ } else {
+#ifndef FOR_R_TDA
+ std::cerr << "Warning: point with 0 persistence ignored in " << fname << ":" << lineNumber << "\n";
+#endif
+ }
+ }
+ catch (const std::invalid_argument& e) {
+#ifndef FOR_R_TDA
+ std::cerr << "Error in file " << fname << ", line number " << lineNumber << ": cannot parse \"" << line << "\"" << std::endl;
+#endif
+ return false;
+ }
+ catch (const std::out_of_range&) {
+#ifndef FOR_R_TDA
+ std::cerr << "Error while reading file " << fname << ", line number " << lineNumber << ": value too large in \"" << line << "\"" << std::endl;
+#endif
+ return false;
+ }
+ }
+ f.close();
+ return true;
+}
+
+
+// wrappers
+template<class RealType = double, class ContType_ = std::vector<std::pair<RealType, RealType>>>
+inline bool read_diagram_point_set(const std::string& fname, ContType_& result, int& decPrecision)
+{
+ return read_diagram_point_set<RealType, ContType_>(fname.c_str(), result, decPrecision);
+}
+
+// these two functions are now just wrappers for the previous ones,
+// in case someone needs them; decPrecision is ignored
+template<class RealType = double, class ContType_ = std::vector<std::pair<RealType, RealType>>>
+inline bool read_diagram_point_set(const char* fname, ContType_& result)
+{
+ int decPrecision;
+ return read_diagram_point_set<RealType, ContType_>(fname, result, decPrecision);
+}
+
+template<class RealType = double, class ContType_ = std::vector<std::pair<RealType, RealType>>>
+inline bool read_diagram_point_set(const std::string& fname, ContType_& result)
+{
+ int decPrecision;
+ return read_diagram_point_set<RealType, ContType_>(fname.c_str(), result, decPrecision);
+}
+
+template<class RealType = double, class ContType_ = std::vector<std::pair<RealType, RealType> > >
+inline bool read_diagram_dipha(const std::string& fname, unsigned int dim, ContType_& result)
+{
+ std::ifstream file;
+ file.open(fname, std::ios::in | std::ios::binary);
+
+ if (!file.is_open()) {
+#ifndef FOR_R_TDA
+ std::cerr << "Could not open file " << fname << "." << std::endl;
+#endif
+ return false;
+ }
+
+ if (read_le<int64_t>(file) != DIPHA_MAGIC) {
+#ifndef FOR_R_TDA
+ std::cerr << "File " << fname << " is not a valid DIPHA file." << std::endl;
+#endif
+ file.close();
+ return false;
+ }
+
+ if (read_le<int64_t>(file) != DIPHA_PERSISTENCE_DIAGRAM) {
+#ifndef FOR_R_TDA
+ std::cerr << "File " << fname << " is not a valid DIPHA persistence diagram file." << std::endl;
+#endif
+ file.close();
+ return false;
+ }
+
+ result.clear();
+
+ int n = read_le<int64_t>(file);
+
+ for (int i = 0; i < n; ++i) {
+ int tmp_d = read_le<int64_t>(file);
+ double birth = read_le<double>(file);
+ double death = read_le<double>(file);
+
+ if (death < birth) {
+#ifndef FOR_R_TDA
+ std::cerr << "File " << fname << " is malformed." << std::endl;
+#endif
+ file.close();
+ return false;
+ }
+
+ int d = 0;
+ if (tmp_d < 0) {
+ d = -tmp_d - 1;
+ death = std::numeric_limits<double>::infinity();
+ } else
+ d = tmp_d;
+
+ if ((unsigned int)d == dim) {
+ if (death == birth) {
+#ifndef FOR_R_TDA
+ std::cerr << "Warning: point with 0 persistence ignored in " << fname << "." << std::endl;
+#endif
+ } else {
+ result.push_back(std::make_pair(birth, death));
+ }
+ }
+ }
+
+ file.close();
+
+ return true;
+}
+
+
+template<class RealType, class ContType>
+inline void remove_duplicates(ContType& dgm_A, ContType& dgm_B)
+{
+ std::map<std::pair<RealType, RealType>, int> map_A, map_B;
+ // copy points to maps
+ for(const auto& ptA : dgm_A) {
+ map_A[ptA]++;
+ }
+ for(const auto& ptB : dgm_B) {
+ map_B[ptB]++;
+ }
+ // clear vectors
+ dgm_A.clear();
+ dgm_B.clear();
+ // remove duplicates from maps
+ // loop over the smaller one
+ if (map_A.size() <= map_B.size()) {
+ for(auto& point_multiplicity_pair : map_A) {
+ auto iter_B = map_B.find(point_multiplicity_pair.first);
+ if (iter_B != map_B.end()) {
+ int duplicate_multiplicity = std::min(point_multiplicity_pair.second, iter_B->second);
+ point_multiplicity_pair.second -= duplicate_multiplicity;
+ iter_B->second -= duplicate_multiplicity;
+ }
+ }
+ } else {
+ for(auto& point_multiplicity_pair : map_B) {
+ auto iter_A = map_A.find(point_multiplicity_pair.first);
+ if (iter_A != map_A.end()) {
+ int duplicate_multiplicity = std::min(point_multiplicity_pair.second, iter_A->second);
+ point_multiplicity_pair.second -= duplicate_multiplicity;
+ iter_A->second -= duplicate_multiplicity;
+ }
+ }
+ }
+ // copy points back to vectors
+ for(const auto& pointMultiplicityPairA : map_A) {
+ assert( pointMultiplicityPairA.second >= 0);
+ for(int i = 0; i < pointMultiplicityPairA.second; ++i) {
+ dgm_A.push_back(pointMultiplicityPairA.first);
+ }
+ }
+
+ for(const auto& pointMultiplicityPairB : map_B) {
+ assert( pointMultiplicityPairB.second >= 0);
+ for(int i = 0; i < pointMultiplicityPairB.second; ++i) {
+ dgm_B.push_back(pointMultiplicityPairB.first);
+ }
+ }
+}
+
+
+#ifdef WASSERSTEIN_PURE_GEOM
+
+template<class Real>
+inline int get_point_dimension(const std::string& line)
+{
+ Real x;
+ int dim = 0;
+ std::istringstream iss(line);
+ while(iss >> x) {
+ dim++;
+ }
+ return dim;
+}
+
+
+template<class RealType = double >
+inline bool read_point_cloud(const char* fname, hera::ws::dnn::DynamicPointVector<RealType>& result, int& dimension, int& decPrecision)
+{
+ using DynamicPointTraitsR = typename hera::ws::dnn::DynamicPointTraits<RealType>;
+
+ size_t lineNumber { 0 };
+ result.clear();
+ std::ifstream f(fname);
+ if (!f.good()) {
+#ifndef FOR_R_TDA
+ std::cerr << "Cannot open file " << fname << std::endl;
+#endif
+ return false;
+ }
+ std::string line;
+ DynamicPointTraitsR traits;
+ bool dim_computed = false;
+ int point_idx = 0;
+ while(std::getline(f, line)) {
+ lineNumber++;
+ // process comments: remove everything after hash
+ auto hashPos = line.find_first_of("#", 0);
+ if( std::string::npos != hashPos) {
+ line = std::string(line.begin(), line.begin() + hashPos);
+ }
+ if (line.empty()) {
+ continue;
+ }
+ // trim whitespaces
+ auto whiteSpaceFront = std::find_if_not(line.begin(),line.end(),isspace);
+ auto whiteSpaceBack = std::find_if_not(line.rbegin(),line.rend(),isspace).base();
+ if (whiteSpaceBack <= whiteSpaceFront) {
+ // line consists of spaces only - move to the next line
+ continue;
+ }
+
+ line = std::string(whiteSpaceFront,whiteSpaceBack);
+
+ if (not dim_computed) {
+ dimension = get_point_dimension<RealType>(line);
+ traits = hera::ws::dnn::DynamicPointTraits<RealType>(dimension);
+ result = traits.container();
+ result.clear();
+ dim_computed = true;
+ }
+
+ bool fracPart = false;
+ int currDecPrecision = 0;
+ for(auto c : line) {
+ if (c == '.') {
+ fracPart = true;
+ } else if (fracPart) {
+ if (isdigit(c)) {
+ currDecPrecision++;
+ } else {
+ fracPart = false;
+ if (currDecPrecision > decPrecision)
+ decPrecision = currDecPrecision;
+ currDecPrecision = 0;
+ }
+ }
+ }
+
+ result.resize(result.size() + 1);
+ RealType x;
+ std::istringstream iss(line);
+ for(int d = 0; d < dimension; ++d) {
+ if (not(iss >> x)) {
+#ifndef FOR_R_TDA
+ std::cerr << "Error in file " << fname << ", line number " << lineNumber << ": cannot parse \"" << line << "\"" << std::endl;
+#endif
+ return false;
+ }
+ result[point_idx][d] = x;
+ }
+ point_idx++;
+ }
+ f.close();
+ return true;
+}
+
+// wrappers
+template<class RealType = double >
+inline bool read_point_cloud(const char* fname, hera::ws::dnn::DynamicPointVector<RealType>& result, int& dimension)
+{
+ int dec_precision;
+ return read_point_cloud<RealType>(fname, result, dimension, dec_precision);
+}
+
+template<class RealType = double >
+inline bool read_point_cloud(std::string fname, hera::ws::dnn::DynamicPointVector<RealType>& result, int& dimension, int& dec_precision)
+{
+ return read_point_cloud<RealType>(fname.c_str(), result, dimension, dec_precision);
+}
+
+template<class RealType = double >
+inline bool read_point_cloud(std::string fname, hera::ws::dnn::DynamicPointVector<RealType>& result, int& dimension)
+{
+ return read_point_cloud<RealType>(fname.c_str(), result, dimension);
+}
+
+#endif // WASSERSTEIN_PURE_GEOM
+
+} // end namespace hera
+#endif // HERA_DIAGRAM_READER_H
diff --git a/wasserstein/include/dnn/geometry/euclidean-dynamic.h b/wasserstein/include/dnn/geometry/euclidean-dynamic.h
new file mode 100644
index 0000000..b003906
--- /dev/null
+++ b/wasserstein/include/dnn/geometry/euclidean-dynamic.h
@@ -0,0 +1,270 @@
+#ifndef DNN_GEOMETRY_EUCLIDEAN_DYNAMIC_H
+#define DNN_GEOMETRY_EUCLIDEAN_DYNAMIC_H
+
+#include <vector>
+#include <algorithm>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/vector.hpp>
+#include <cmath>
+
+#include "hera_infinity.h"
+
+namespace hera
+{
+namespace ws
+{
+namespace dnn
+{
+
+template<class Real_>
+class DynamicPointVector
+{
+ public:
+ using Real = Real_;
+ struct PointType
+ {
+ void* p;
+
+ Real& operator[](const int i)
+ {
+ return (static_cast<Real*>(p))[i];
+ }
+
+ const Real& operator[](const int i) const
+ {
+ return (static_cast<Real*>(p))[i];
+ }
+
+ };
+ struct iterator;
+ typedef iterator const_iterator;
+
+ public:
+ DynamicPointVector(size_t point_capacity = 0):
+ point_capacity_(point_capacity) {}
+
+
+ PointType operator[](size_t i) const { return {(void*) &storage_[i*point_capacity_]}; }
+ inline void push_back(PointType p);
+
+ inline iterator begin();
+ inline iterator end();
+ inline const_iterator begin() const;
+ inline const_iterator end() const;
+
+ size_t size() const { return storage_.size() / point_capacity_; }
+
+ void clear() { storage_.clear(); }
+ void swap(DynamicPointVector& other) { storage_.swap(other.storage_); std::swap(point_capacity_, other.point_capacity_); }
+ void reserve(size_t sz) { storage_.reserve(sz * point_capacity_); }
+ void resize(size_t sz) { storage_.resize(sz * point_capacity_); }
+
+ private:
+ size_t point_capacity_;
+ std::vector<char> storage_;
+
+ private:
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive& ar, const unsigned int version) { ar & point_capacity_ & storage_; }
+};
+
+template<typename Real>
+struct DynamicPointTraits
+{
+ typedef DynamicPointVector<Real> PointContainer;
+ typedef typename PointContainer::PointType PointType;
+ struct PointHandle
+ {
+ void* p;
+ bool operator==(const PointHandle& other) const { return p == other.p; }
+ bool operator!=(const PointHandle& other) const { return !(*this == other); }
+ bool operator<(const PointHandle& other) const { return p < other.p; }
+ bool operator>(const PointHandle& other) const { return p > other.p; }
+ };
+
+ typedef Real Coordinate;
+ typedef Real DistanceType;
+
+ DynamicPointTraits(unsigned dim = 0):
+ dim_(dim) {}
+
+ DistanceType distance(PointType p1, PointType p2) const
+ {
+ Real result = 0.0;
+ if (hera::is_infinity(internal_p)) {
+ // max norm
+ for (unsigned i = 0; i < dimension(); ++i)
+ result = std::max(result, fabs(coordinate(p1,i) - coordinate(p2,i)));
+ } else if (internal_p == Real(1.0)) {
+ // l1-norm
+ for (unsigned i = 0; i < dimension(); ++i)
+ result += fabs(coordinate(p1,i) - coordinate(p2,i));
+ } else if (internal_p == Real(2.0)) {
+ result = sqrt(sq_distance(p1,p2));
+ } else {
+ assert(internal_p > 1.0);
+ for (unsigned i = 0; i < dimension(); ++i)
+ result += std::pow(fabs(coordinate(p1,i) - coordinate(p2,i)), internal_p);
+ result = std::pow(result, Real(1.0) / internal_p);
+ }
+ return result;
+ }
+ DistanceType distance(PointHandle p1, PointHandle p2) const { return distance(PointType({p1.p}), PointType({p2.p})); }
+ DistanceType sq_distance(PointType p1, PointType p2) const { Real res = 0; for (unsigned i = 0; i < dimension(); ++i) { Real c1 = coordinate(p1,i), c2 = coordinate(p2,i); res += (c1 - c2)*(c1 - c2); } return res; }
+ DistanceType sq_distance(PointHandle p1, PointHandle p2) const { return sq_distance(PointType({p1.p}), PointType({p2.p})); }
+ unsigned dimension() const { return dim_; }
+ Real& coordinate(PointType p, unsigned i) const { return ((Real*) p.p)[i]; }
+ Real& coordinate(PointHandle h, unsigned i) const { return ((Real*) h.p)[i]; }
+
+ // it's non-standard to return a reference, but we can rely on it for code that assumes this particular point type
+ size_t& id(PointType p) const { return *((size_t*) ((Real*) p.p + dimension())); }
+ size_t& id(PointHandle h) const { return *((size_t*) ((Real*) h.p + dimension())); }
+ PointHandle handle(PointType p) const { return {p.p}; }
+ PointType point(PointHandle h) const { return {h.p}; }
+
+ void swap(PointType p1, PointType p2) const { std::swap_ranges((char*) p1.p, ((char*) p1.p) + capacity(), (char*) p2.p); }
+ bool cmp(PointType p1, PointType p2) const { return std::lexicographical_compare((Real*) p1.p, ((Real*) p1.p) + dimension(), (Real*) p2.p, ((Real*) p2.p) + dimension()); }
+ bool eq(PointType p1, PointType p2) const { return std::equal((Real*) p1.p, ((Real*) p1.p) + dimension(), (Real*) p2.p); }
+
+ // non-standard, and possibly a weird name
+ size_t capacity() const { return sizeof(Real)*dimension() + sizeof(size_t); }
+
+ PointContainer container(size_t n = 0) const { PointContainer c(capacity()); c.resize(n); return c; }
+ PointContainer container(size_t n, const PointType& p) const;
+
+ typename PointContainer::iterator
+ iterator(PointContainer& c, PointHandle ph) const;
+ typename PointContainer::const_iterator
+ iterator(const PointContainer& c, PointHandle ph) const;
+
+ Real internal_p;
+
+ private:
+ unsigned dim_;
+
+ private:
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive& ar, const unsigned int version) { ar & dim_; }
+};
+
+} // dnn
+
+template<class Real>
+struct dnn::DynamicPointVector<Real>::iterator:
+ public boost::iterator_facade<iterator,
+ PointType,
+ std::random_access_iterator_tag,
+ PointType,
+ std::ptrdiff_t>
+{
+ typedef boost::iterator_facade<iterator,
+ PointType,
+ std::random_access_iterator_tag,
+ PointType,
+ std::ptrdiff_t> Parent;
+
+
+ public:
+ typedef typename Parent::value_type value_type;
+ typedef typename Parent::difference_type difference_type;
+ typedef typename Parent::reference reference;
+
+ iterator(size_t point_capacity = 0):
+ point_capacity_(point_capacity) {}
+
+ iterator(void* p, size_t point_capacity):
+ p_(p), point_capacity_(point_capacity) {}
+
+ private:
+ void increment() { p_ = ((char*) p_) + point_capacity_; }
+ void decrement() { p_ = ((char*) p_) - point_capacity_; }
+ void advance(difference_type n) { p_ = ((char*) p_) + n*point_capacity_; }
+ difference_type
+ distance_to(iterator other) const { return (((char*) other.p_) - ((char*) p_))/(int) point_capacity_; }
+ bool equal(const iterator& other) const { return p_ == other.p_; }
+ reference dereference() const { return {p_}; }
+
+ friend class ::boost::iterator_core_access;
+
+ private:
+ void* p_;
+ size_t point_capacity_;
+};
+
+template<class Real>
+void dnn::DynamicPointVector<Real>::push_back(PointType p)
+{
+ if (storage_.capacity() < storage_.size() + point_capacity_)
+ storage_.reserve(1.5*storage_.capacity());
+
+ storage_.resize(storage_.size() + point_capacity_);
+
+ std::copy((char*) p.p, (char*) p.p + point_capacity_, storage_.end() - point_capacity_);
+}
+
+template<class Real>
+typename dnn::DynamicPointVector<Real>::iterator dnn::DynamicPointVector<Real>::begin() { return iterator((void*) &*storage_.begin(), point_capacity_); }
+
+template<class Real>
+typename dnn::DynamicPointVector<Real>::iterator dnn::DynamicPointVector<Real>::end() { return iterator((void*) &*storage_.end(), point_capacity_); }
+
+template<class Real>
+typename dnn::DynamicPointVector<Real>::const_iterator dnn::DynamicPointVector<Real>::begin() const { return const_iterator((void*) &*storage_.begin(), point_capacity_); }
+
+template<class Real>
+typename dnn::DynamicPointVector<Real>::const_iterator dnn::DynamicPointVector<Real>::end() const { return const_iterator((void*) &*storage_.end(), point_capacity_); }
+
+template<typename R>
+typename dnn::DynamicPointTraits<R>::PointContainer
+dnn::DynamicPointTraits<R>::container(size_t n, const PointType& p) const
+{
+ PointContainer c = container(n);
+ for (auto x : c)
+ std::copy((char*) p.p, (char*) p.p + capacity(), (char*) x.p);
+ return c;
+}
+
+template<typename R>
+typename dnn::DynamicPointTraits<R>::PointContainer::iterator
+dnn::DynamicPointTraits<R>::iterator(PointContainer& c, PointHandle ph) const
+{ return typename PointContainer::iterator(ph.p, capacity()); }
+
+template<typename R>
+typename dnn::DynamicPointTraits<R>::PointContainer::const_iterator
+dnn::DynamicPointTraits<R>::iterator(const PointContainer& c, PointHandle ph) const
+{ return typename PointContainer::const_iterator(ph.p, capacity()); }
+
+} // ws
+} // hera
+
+namespace std {
+ template<>
+ struct hash<typename hera::ws::dnn::DynamicPointTraits<double>::PointHandle>
+ {
+ using PointHandle = typename hera::ws::dnn::DynamicPointTraits<double>::PointHandle;
+ size_t operator()(const PointHandle& ph) const
+ {
+ return std::hash<void*>()(ph.p);
+ }
+ };
+
+ template<>
+ struct hash<typename hera::ws::dnn::DynamicPointTraits<float>::PointHandle>
+ {
+ using PointHandle = typename hera::ws::dnn::DynamicPointTraits<float>::PointHandle;
+ size_t operator()(const PointHandle& ph) const
+ {
+ return std::hash<void*>()(ph.p);
+ }
+ };
+
+
+} // std
+
+
+#endif
diff --git a/wasserstein/include/dnn/geometry/euclidean-fixed.h b/wasserstein/include/dnn/geometry/euclidean-fixed.h
new file mode 100644
index 0000000..3e38baf
--- /dev/null
+++ b/wasserstein/include/dnn/geometry/euclidean-fixed.h
@@ -0,0 +1,196 @@
+#ifndef HERA_WS_DNN_GEOMETRY_EUCLIDEAN_FIXED_H
+#define HERA_WS_DNN_GEOMETRY_EUCLIDEAN_FIXED_H
+
+#include <boost/operators.hpp>
+#include <boost/array.hpp>
+#include <boost/range/value_type.hpp>
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/base_object.hpp>
+
+//#include <iostream>
+#include <fstream>
+#include <string>
+#include <sstream>
+#include <cmath>
+
+#include "../parallel/tbb.h" // for dnn::vector<...>
+
+namespace hera
+{
+namespace ws
+{
+namespace dnn
+{
+ // TODO: wrap in another namespace (e.g., euclidean)
+
+ template<size_t D, typename Real = double>
+ struct Point:
+ boost::addable< Point<D,Real>,
+ boost::subtractable< Point<D,Real>,
+ boost::dividable2< Point<D, Real>, Real,
+ boost::multipliable2< Point<D, Real>, Real > > > >,
+ public boost::array<Real, D>
+ {
+ public:
+ typedef Real Coordinate;
+ typedef Real DistanceType;
+
+
+ public:
+ Point(size_t id = 0): id_(id) {}
+ template<size_t DD>
+ Point(const Point<DD,Real>& p, size_t id = 0):
+ id_(id) { *this = p; }
+
+ static size_t dimension() { return D; }
+
+ // Assign a point of different dimension
+ template<size_t DD>
+ Point& operator=(const Point<DD,Real>& p) { for (size_t i = 0; i < (D < DD ? D : DD); ++i) (*this)[i] = p[i]; if (DD < D) for (size_t i = DD; i < D; ++i) (*this)[i] = 0; return *this; }
+
+ Point& operator+=(const Point& p) { for (size_t i = 0; i < D; ++i) (*this)[i] += p[i]; return *this; }
+ Point& operator-=(const Point& p) { for (size_t i = 0; i < D; ++i) (*this)[i] -= p[i]; return *this; }
+ Point& operator/=(Real r) { for (size_t i = 0; i < D; ++i) (*this)[i] /= r; return *this; }
+ Point& operator*=(Real r) { for (size_t i = 0; i < D; ++i) (*this)[i] *= r; return *this; }
+
+ Real norm2() const { Real n = 0; for (size_t i = 0; i < D; ++i) n += (*this)[i] * (*this)[i]; return n; }
+ Real max_norm() const
+ {
+ Real res = std::fabs((*this)[0]);
+ for (size_t i = 1; i < D; ++i)
+ if (std::fabs((*this)[i]) > res)
+ res = std::fabs((*this)[i]);
+ return res;
+ }
+
+ Real l1_norm() const
+ {
+ Real res = std::fabs((*this)[0]);
+ for (size_t i = 1; i < D; ++i)
+ res += std::fabs((*this)[i]);
+ return res;
+ }
+
+ Real lp_norm(const Real p) const
+ {
+ assert( !std::isinf(p) );
+ if ( p == 1.0 )
+ return l1_norm();
+ Real res = std::pow(std::fabs((*this)[0]), p);
+ for (size_t i = 1; i < D; ++i)
+ res += std::pow(std::fabs((*this)[i]), p);
+ return std::pow(res, 1.0 / p);
+ }
+
+ // quick and dirty for now; make generic later
+ //DistanceType distance(const Point& other) const { return sqrt(sq_distance(other)); }
+ //DistanceType sq_distance(const Point& other) const { return (other - *this).norm2(); }
+
+ DistanceType distance(const Point& other) const { return (other - *this).max_norm(); }
+ DistanceType p_distance(const Point& other, const double p) const { return (other - *this).lp_norm(p); }
+
+ size_t id() const { return id_; }
+ size_t& id() { return id_; }
+
+ private:
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive& ar, const unsigned int version) { ar & boost::serialization::base_object< boost::array<Real,D> >(*this) & id_; }
+
+ private:
+ size_t id_;
+ };
+
+ template<size_t D, typename Real>
+ std::ostream&
+ operator<<(std::ostream& out, const Point<D,Real>& p)
+ { out << p[0]; for (size_t i = 1; i < D; ++i) out << " " << p[i]; return out; }
+
+
+ template<class Point>
+ struct PointTraits; // intentionally undefined; should be specialized for each type
+
+
+ template<size_t D, typename Real>
+ struct PointTraits< Point<D, Real> > // specialization for dnn::Point
+ {
+ typedef Point<D,Real> PointType;
+ typedef const PointType* PointHandle;
+ typedef std::vector<PointType> PointContainer;
+
+ typedef typename PointType::Coordinate Coordinate;
+ typedef typename PointType::DistanceType DistanceType;
+
+
+ static DistanceType
+ distance(const PointType& p1, const PointType& p2) { if (hera::is_infinity(internal_p)) return p1.distance(p2); else return p1.p_distance(p2, internal_p); }
+
+ static DistanceType
+ distance(PointHandle p1, PointHandle p2) { return distance(*p1,*p2); }
+
+ static size_t dimension() { return D; }
+ static Real coordinate(const PointType& p, size_t i) { return p[i]; }
+ static Real& coordinate(PointType& p, size_t i) { return p[i]; }
+ static Real coordinate(PointHandle p, size_t i) { return coordinate(*p,i); }
+
+ static size_t id(const PointType& p) { return p.id(); }
+ static size_t& id(PointType& p) { return p.id(); }
+ static size_t id(PointHandle p) { return id(*p); }
+
+ static PointHandle
+ handle(const PointType& p) { return &p; }
+ static const PointType&
+ point(PointHandle ph) { return *ph; }
+
+ void swap(PointType& p1, PointType& p2) const { return std::swap(p1, p2); }
+
+ static PointContainer
+ container(size_t n = 0, const PointType& p = PointType()) { return PointContainer(n, p); }
+ static typename PointContainer::iterator
+ iterator(PointContainer& c, PointHandle ph) { return c.begin() + (ph - &c[0]); }
+ static typename PointContainer::const_iterator
+ iterator(const PointContainer& c, PointHandle ph) { return c.begin() + (ph - &c[0]); }
+
+ // Internal_p determines which norm will be used in Wasserstein metric (not to
+ // be confused with wassersteinPower parameter:
+ // we raise \| p - q \|_{internal_p} to wassersteinPower.
+ static Real internal_p;
+
+ private:
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive& ar, const unsigned int version) {}
+
+ };
+
+ template<size_t D, typename Real>
+ Real PointTraits< Point<D, Real> >::internal_p = hera::get_infinity<Real>();
+
+
+ template<class PointContainer>
+ void read_points(const std::string& filename, PointContainer& points)
+ {
+ typedef typename boost::range_value<PointContainer>::type Point;
+ typedef typename PointTraits<Point>::Coordinate Coordinate;
+
+ std::ifstream in(filename.c_str());
+ std::string line;
+ while(std::getline(in, line))
+ {
+ if (line[0] == '#') continue; // comment line in the file
+ std::stringstream linestream(line);
+ Coordinate x;
+ points.push_back(Point());
+ size_t i = 0;
+ while (linestream >> x)
+ points.back()[i++] = x;
+ }
+ }
+} // dnn
+} // ws
+} // hera
+
+#endif
diff --git a/wasserstein/include/dnn/local/kd-tree.h b/wasserstein/include/dnn/local/kd-tree.h
new file mode 100644
index 0000000..8e52a5c
--- /dev/null
+++ b/wasserstein/include/dnn/local/kd-tree.h
@@ -0,0 +1,97 @@
+#ifndef HERA_WS_DNN_LOCAL_KD_TREE_H
+#define HERA_WS_DNN_LOCAL_KD_TREE_H
+
+#include "../utils.h"
+#include "search-functors.h"
+
+#include <unordered_map>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/range/value_type.hpp>
+
+#include <boost/static_assert.hpp>
+#include <boost/type_traits.hpp>
+
+namespace hera
+{
+namespace ws
+{
+namespace dnn
+{
+ // Weighted KDTree
+ // Traits_ provides Coordinate, DistanceType, PointType, dimension(), distance(p1,p2), coordinate(p,i)
+ template< class Traits_ >
+ class KDTree
+ {
+ public:
+ typedef Traits_ Traits;
+ typedef dnn::HandleDistance<KDTree> HandleDistance;
+
+ typedef typename Traits::PointType Point;
+ typedef typename Traits::PointHandle PointHandle;
+ typedef typename Traits::Coordinate Coordinate;
+ typedef typename Traits::DistanceType DistanceType;
+ typedef std::vector<PointHandle> HandleContainer;
+ typedef std::vector<HandleDistance> HDContainer; // TODO: use tbb::scalable_allocator
+ typedef HDContainer Result;
+ typedef std::vector<DistanceType> DistanceContainer;
+ typedef std::unordered_map<PointHandle, size_t> HandleMap;
+
+ BOOST_STATIC_ASSERT_MSG(has_coordinates<Traits, PointHandle, int>::value, "KDTree requires coordinates");
+
+ public:
+ KDTree(const Traits& traits):
+ traits_(traits) {}
+
+ KDTree(const Traits& traits, HandleContainer&& handles, double _wassersteinPower = 1.0);
+
+ template<class Range>
+ KDTree(const Traits& traits, const Range& range, double _wassersteinPower = 1.0);
+
+ template<class Range>
+ void init(const Range& range);
+
+ DistanceType weight(PointHandle p) { return weights_[indices_[p]]; }
+ void change_weight(PointHandle p, DistanceType w);
+ void adjust_weights(DistanceType delta); // subtract delta from all weights
+
+ HandleDistance find(PointHandle q) const;
+ Result findR(PointHandle q, DistanceType r) const; // all neighbors within r
+ Result findK(PointHandle q, size_t k) const; // k nearest neighbors
+
+ HandleDistance find(const Point& q) const { return find(traits().handle(q)); }
+ Result findR(const Point& q, DistanceType r) const { return findR(traits().handle(q), r); }
+ Result findK(const Point& q, size_t k) const { return findK(traits().handle(q), k); }
+
+ template<class ResultsFunctor>
+ void search(PointHandle q, ResultsFunctor& rf) const;
+
+ const Traits& traits() const { return traits_; }
+
+ void printWeights(void);
+
+ private:
+ void init();
+
+ typedef typename HandleContainer::iterator HCIterator;
+ typedef std::tuple<HCIterator, HCIterator, size_t> KDTreeNode;
+
+ struct CoordinateComparison;
+ struct OrderTree;
+
+ private:
+ Traits traits_;
+ HandleContainer tree_;
+ DistanceContainer weights_; // point weight
+ DistanceContainer subtree_weights_; // min weight in the subtree
+ HandleMap indices_;
+ double wassersteinPower;
+ };
+} // dnn
+} // ws
+} // hera
+
+#include "kd-tree.hpp"
+
+#endif
diff --git a/wasserstein/include/dnn/local/kd-tree.hpp b/wasserstein/include/dnn/local/kd-tree.hpp
new file mode 100644
index 0000000..bdeef45
--- /dev/null
+++ b/wasserstein/include/dnn/local/kd-tree.hpp
@@ -0,0 +1,330 @@
+#include <boost/range/counting_range.hpp>
+#include <boost/range/algorithm_ext/push_back.hpp>
+#include <boost/range.hpp>
+
+#include <queue>
+#include <stack>
+
+#include "../parallel/tbb.h"
+#include "def_debug_ws.h"
+
+template<class T>
+hera::ws::dnn::KDTree<T>::
+KDTree(const Traits& traits, HandleContainer&& handles, double _wassersteinPower):
+ traits_(traits), tree_(std::move(handles)), wassersteinPower(_wassersteinPower)
+{ assert(wassersteinPower >= 1.0); init(); }
+
+template<class T>
+template<class Range>
+hera::ws::dnn::KDTree<T>::
+KDTree(const Traits& traits, const Range& range, double _wassersteinPower):
+ traits_(traits), wassersteinPower(_wassersteinPower)
+{
+ assert( wassersteinPower >= 1.0);
+ init(range);
+}
+
+template<class T>
+template<class Range>
+void
+hera::ws::dnn::KDTree<T>::
+init(const Range& range)
+{
+ size_t sz = std::distance(std::begin(range), std::end(range));
+ tree_.reserve(sz);
+ weights_.resize(sz, 0);
+ subtree_weights_.resize(sz, 0);
+ for (PointHandle h : range)
+ tree_.push_back(h);
+ init();
+}
+
+template<class T>
+void
+hera::ws::dnn::KDTree<T>::
+init()
+{
+ if (tree_.empty())
+ return;
+
+#if defined(TBB)
+ task_group g;
+ g.run(OrderTree(tree_.begin(), tree_.end(), 0, traits()));
+ g.wait();
+#else
+ OrderTree(tree_.begin(), tree_.end(), 0, traits()).serial();
+#endif
+
+ for (size_t i = 0; i < tree_.size(); ++i)
+ indices_[tree_[i]] = i;
+}
+
+template<class T>
+struct
+hera::ws::dnn::KDTree<T>::OrderTree
+{
+ OrderTree(HCIterator b_, HCIterator e_, size_t i_, const Traits& traits_):
+ b(b_), e(e_), i(i_), traits(traits_) {}
+
+ void operator()() const
+ {
+ if (e - b < 1000)
+ {
+ serial();
+ return;
+ }
+
+ HCIterator m = b + (e - b)/2;
+ CoordinateComparison cmp(i, traits);
+ std::nth_element(b,m,e, cmp);
+ size_t next_i = (i + 1) % traits.dimension();
+
+ task_group g;
+ if (b < m - 1) g.run(OrderTree(b, m, next_i, traits));
+ if (e > m + 2) g.run(OrderTree(m+1, e, next_i, traits));
+ g.wait();
+ }
+
+ void serial() const
+ {
+ std::queue<KDTreeNode> q;
+ q.push(KDTreeNode(b,e,i));
+ while (!q.empty())
+ {
+ HCIterator b, e; size_t i;
+ std::tie(b,e,i) = q.front();
+ q.pop();
+ HCIterator m = b + (e - b)/2;
+
+ CoordinateComparison cmp(i, traits);
+ std::nth_element(b,m,e, cmp);
+ size_t next_i = (i + 1) % traits.dimension();
+
+ // Replace with a size condition instead?
+ if (m - b > 1) q.push(KDTreeNode(b, m, next_i));
+ if (e - m > 2) q.push(KDTreeNode(m+1, e, next_i));
+ }
+ }
+
+ HCIterator b, e;
+ size_t i;
+ const Traits& traits;
+};
+
+template<class T>
+template<class ResultsFunctor>
+void
+hera::ws::dnn::KDTree<T>::
+search(PointHandle q, ResultsFunctor& rf) const
+{
+ typedef typename HandleContainer::const_iterator HCIterator;
+ typedef std::tuple<HCIterator, HCIterator, size_t> KDTreeNode;
+
+ if (tree_.empty())
+ return;
+
+ DistanceType D = std::numeric_limits<DistanceType>::max();
+
+ // TODO: use tbb::scalable_allocator for the queue
+ std::queue<KDTreeNode> nodes;
+
+ nodes.push(KDTreeNode(tree_.begin(), tree_.end(), 0));
+
+ while (!nodes.empty())
+ {
+ HCIterator b, e; size_t i;
+ std::tie(b,e,i) = nodes.front();
+ nodes.pop();
+
+ CoordinateComparison cmp(i, traits());
+ i = (i + 1) % traits().dimension();
+
+ HCIterator m = b + (e - b)/2;
+
+ DistanceType dist = (wassersteinPower == 1.0) ? traits().distance(q, *m) + weights_[m - tree_.begin()] : std::pow(traits().distance(q, *m), wassersteinPower) + weights_[m - tree_.begin()];
+
+
+ D = rf(*m, dist);
+
+ // we are really searching w.r.t L_\infty ball; could prune better with an L_2 ball
+ Coordinate diff = cmp.diff(q, *m); // diff returns signed distance
+
+ DistanceType diffToWasserPower = (wassersteinPower == 1.0) ? diff : ((diff > 0 ? 1.0 : -1.0) * std::pow(fabs(diff), wassersteinPower));
+
+ size_t lm = m + 1 + (e - (m+1))/2 - tree_.begin();
+ if (e > m + 1 && diffToWasserPower - subtree_weights_[lm] >= -D) {
+ nodes.push(KDTreeNode(m+1, e, i));
+ }
+
+ size_t rm = b + (m - b) / 2 - tree_.begin();
+ if (b < m && diffToWasserPower + subtree_weights_[rm] <= D) {
+ nodes.push(KDTreeNode(b, m, i));
+ }
+ }
+}
+
+template<class T>
+void
+hera::ws::dnn::KDTree<T>::
+adjust_weights(DistanceType delta)
+{
+ for(auto& w : weights_)
+ w -= delta;
+
+ for(auto& sw : subtree_weights_)
+ sw -= delta;
+}
+
+
+template<class T>
+void
+hera::ws::dnn::KDTree<T>::
+change_weight(PointHandle p, DistanceType w)
+{
+ size_t idx = indices_[p];
+
+ if ( weights_[idx] == w ) {
+ return;
+ }
+
+ bool weight_increases = ( weights_[idx] < w );
+ weights_[idx] = w;
+
+ typedef std::tuple<HCIterator, HCIterator> KDTreeNode;
+
+ // find the path down the tree to this node
+ // not an ideal strategy, but // it's not clear how to move up from the node in general
+ std::stack<KDTreeNode> s;
+ s.push(KDTreeNode(tree_.begin(),tree_.end()));
+
+ do
+ {
+ HCIterator b,e;
+ std::tie(b,e) = s.top();
+
+ size_t im = b + (e - b)/2 - tree_.begin();
+
+ if (idx == im)
+ break;
+ else if (idx < im)
+ s.push(KDTreeNode(b, tree_.begin() + im));
+ else // idx > im
+ s.push(KDTreeNode(tree_.begin() + im + 1, e));
+ } while(1);
+
+ // update subtree_weights_ on the path to the root
+ DistanceType min_w = w;
+ while (!s.empty())
+ {
+ HCIterator b,e;
+ std::tie(b,e) = s.top();
+ HCIterator m = b + (e - b)/2;
+ size_t im = m - tree_.begin();
+ s.pop();
+
+
+ // left and right children
+ if (b < m)
+ {
+ size_t lm = b + (m - b)/2 - tree_.begin();
+ if (subtree_weights_[lm] < min_w)
+ min_w = subtree_weights_[lm];
+ }
+
+ if (e > m + 1)
+ {
+ size_t rm = m + 1 + (e - (m+1))/2 - tree_.begin();
+ if (subtree_weights_[rm] < min_w)
+ min_w = subtree_weights_[rm];
+ }
+
+ if (weights_[im] < min_w) {
+ min_w = weights_[im];
+ }
+
+ if (weight_increases) {
+
+ if (subtree_weights_[im] < min_w ) // increase weight
+ subtree_weights_[im] = min_w;
+ else
+ break;
+
+ } else {
+
+ if (subtree_weights_[im] > min_w ) // decrease weight
+ subtree_weights_[im] = min_w;
+ else
+ break;
+
+ }
+ }
+}
+
+template<class T>
+typename hera::ws::dnn::KDTree<T>::HandleDistance
+hera::ws::dnn::KDTree<T>::
+find(PointHandle q) const
+{
+ hera::ws::dnn::NNRecord<HandleDistance> nn;
+ search(q, nn);
+ return nn.result;
+}
+
+template<class T>
+typename hera::ws::dnn::KDTree<T>::Result
+hera::ws::dnn::KDTree<T>::
+findR(PointHandle q, DistanceType r) const
+{
+ hera::ws::dnn::rNNRecord<HandleDistance> rnn(r);
+ search(q, rnn);
+ std::sort(rnn.result.begin(), rnn.result.end());
+ return rnn.result;
+}
+
+template<class T>
+typename hera::ws::dnn::KDTree<T>::Result
+hera::ws::dnn::KDTree<T>::
+findK(PointHandle q, size_t k) const
+{
+ hera::ws::dnn::kNNRecord<HandleDistance> knn(k);
+ search(q, knn);
+ std::sort(knn.result.begin(), knn.result.end());
+ return knn.result;
+}
+
+
+template<class T>
+struct hera::ws::dnn::KDTree<T>::CoordinateComparison
+{
+ CoordinateComparison(size_t i, const Traits& traits):
+ i_(i), traits_(traits) {}
+
+ bool operator()(PointHandle p1, PointHandle p2) const { return coordinate(p1) < coordinate(p2); }
+ Coordinate diff(PointHandle p1, PointHandle p2) const { return coordinate(p1) - coordinate(p2); }
+
+ Coordinate coordinate(PointHandle p) const { return traits_.coordinate(p, i_); }
+ size_t axis() const { return i_; }
+
+ private:
+ size_t i_;
+ const Traits& traits_;
+};
+
+template<class T>
+void
+hera::ws::dnn::KDTree<T>::
+printWeights(void)
+{
+#ifndef FOR_R_TDA
+ std::cout << "weights_:" << std::endl;
+ for(const auto ph : indices_) {
+ std::cout << "idx = " << ph.second << ": (" << (ph.first)->at(0) << ", " << (ph.first)->at(1) << ") weight = " << weights_[ph.second] << std::endl;
+ }
+ std::cout << "subtree_weights_:" << std::endl;
+ for(size_t idx = 0; idx < subtree_weights_.size(); ++idx) {
+ std::cout << idx << " : " << subtree_weights_[idx] << std::endl;
+ }
+#endif
+}
+
+
diff --git a/wasserstein/include/dnn/local/search-functors.h b/wasserstein/include/dnn/local/search-functors.h
new file mode 100644
index 0000000..1419f22
--- /dev/null
+++ b/wasserstein/include/dnn/local/search-functors.h
@@ -0,0 +1,95 @@
+#ifndef HERA_WS_DNN_LOCAL_SEARCH_FUNCTORS_H
+#define HERA_WS_DNN_LOCAL_SEARCH_FUNCTORS_H
+
+#include <boost/range/algorithm/heap_algorithm.hpp>
+
+namespace hera
+{
+namespace ws
+{
+namespace dnn
+{
+
+template<class NN>
+struct HandleDistance
+{
+ typedef typename NN::PointHandle PointHandle;
+ typedef typename NN::DistanceType DistanceType;
+ typedef typename NN::HDContainer HDContainer;
+
+ HandleDistance() {}
+ HandleDistance(PointHandle pp, DistanceType dd):
+ p(pp), d(dd) {}
+ bool operator<(const HandleDistance& other) const { return d < other.d; }
+
+ PointHandle p;
+ DistanceType d;
+};
+
+template<class HandleDistance>
+struct NNRecord
+{
+ typedef typename HandleDistance::PointHandle PointHandle;
+ typedef typename HandleDistance::DistanceType DistanceType;
+
+ NNRecord() { result.d = std::numeric_limits<DistanceType>::max(); }
+ DistanceType operator()(PointHandle p, DistanceType d) { if (d < result.d) { result.p = p; result.d = d; } return result.d; }
+ HandleDistance result;
+};
+
+template<class HandleDistance>
+struct rNNRecord
+{
+ typedef typename HandleDistance::PointHandle PointHandle;
+ typedef typename HandleDistance::DistanceType DistanceType;
+ typedef typename HandleDistance::HDContainer HDContainer;
+
+ rNNRecord(DistanceType r_): r(r_) {}
+ DistanceType operator()(PointHandle p, DistanceType d)
+ {
+ if (d <= r)
+ result.push_back(HandleDistance(p,d));
+ return r;
+ }
+
+ DistanceType r;
+ HDContainer result;
+};
+
+template<class HandleDistance>
+struct kNNRecord
+{
+ typedef typename HandleDistance::PointHandle PointHandle;
+ typedef typename HandleDistance::DistanceType DistanceType;
+ typedef typename HandleDistance::HDContainer HDContainer;
+
+ kNNRecord(unsigned k_): k(k_) {}
+ DistanceType operator()(PointHandle p, DistanceType d)
+ {
+ if (result.size() < k)
+ {
+ result.push_back(HandleDistance(p,d));
+ boost::push_heap(result);
+ if (result.size() < k)
+ return std::numeric_limits<DistanceType>::max();
+ } else if (d < result[0].d)
+ {
+ boost::pop_heap(result);
+ result.back() = HandleDistance(p,d);
+ boost::push_heap(result);
+ }
+ if ( result.size() > 1 ) {
+ assert( result[0].d >= result[1].d );
+ }
+ return result[0].d;
+ }
+
+ unsigned k;
+ HDContainer result;
+};
+
+} // dnn
+} // ws
+} // hera
+
+#endif // DNN_LOCAL_SEARCH_FUNCTORS_H
diff --git a/wasserstein/include/dnn/parallel/tbb.h b/wasserstein/include/dnn/parallel/tbb.h
new file mode 100644
index 0000000..712f812
--- /dev/null
+++ b/wasserstein/include/dnn/parallel/tbb.h
@@ -0,0 +1,235 @@
+#ifndef HERA_WS_PARALLEL_H
+#define HERA_WS_PARALLEL_H
+
+#include <vector>
+
+#include <boost/range.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+#ifdef TBB
+
+#include <tbb/tbb.h>
+#include <tbb/concurrent_hash_map.h>
+#include <tbb/scalable_allocator.h>
+
+#include <boost/serialization/split_free.hpp>
+#include <boost/serialization/collections_load_imp.hpp>
+#include <boost/serialization/collections_save_imp.hpp>
+
+namespace hera
+{
+namespace ws
+{
+namespace dnn
+{
+ using tbb::mutex;
+ using tbb::task_scheduler_init;
+ using tbb::task_group;
+ using tbb::task;
+
+ template<class T>
+ struct vector
+ {
+ typedef tbb::concurrent_vector<T> type;
+ };
+
+ template<class T>
+ struct atomic
+ {
+ typedef tbb::atomic<T> type;
+ static T compare_and_swap(type& v, T n, T o) { return v.compare_and_swap(n,o); }
+ };
+
+ template<class Iterator, class F>
+ void do_foreach(Iterator begin, Iterator end, const F& f) { tbb::parallel_do(begin, end, f); }
+
+ template<class Range, class F>
+ void for_each_range_(const Range& r, const F& f)
+ {
+ for (typename Range::iterator cur = r.begin(); cur != r.end(); ++cur)
+ f(*cur);
+ }
+
+ template<class F>
+ void for_each_range(size_t from, size_t to, const F& f)
+ {
+ //static tbb::affinity_partitioner ap;
+ //tbb::parallel_for(c.range(), boost::bind(&for_each_range_<typename Container::range_type, F>, _1, f), ap);
+ tbb::parallel_for(from, to, f);
+ }
+
+ template<class Container, class F>
+ void for_each_range(const Container& c, const F& f)
+ {
+ //static tbb::affinity_partitioner ap;
+ //tbb::parallel_for(c.range(), boost::bind(&for_each_range_<typename Container::range_type, F>, _1, f), ap);
+ tbb::parallel_for(c.range(), boost::bind(&for_each_range_<typename Container::const_range_type, F>, _1, f));
+ }
+
+ template<class Container, class F>
+ void for_each_range(Container& c, const F& f)
+ {
+ //static tbb::affinity_partitioner ap;
+ //tbb::parallel_for(c.range(), boost::bind(&for_each_range_<typename Container::range_type, F>, _1, f), ap);
+ tbb::parallel_for(c.range(), boost::bind(&for_each_range_<typename Container::range_type, F>, _1, f));
+ }
+
+ template<class ID, class NodePointer, class IDTraits, class Allocator>
+ struct map_traits
+ {
+ typedef tbb::concurrent_hash_map<ID, NodePointer, IDTraits, Allocator> type;
+ typedef typename type::range_type range;
+ };
+
+ struct progress_timer
+ {
+ progress_timer(): start(tbb::tick_count::now()) {}
+ ~progress_timer()
+ { std::cout << (tbb::tick_count::now() - start).seconds() << " s" << std::endl; }
+
+ tbb::tick_count start;
+ };
+} // dnn
+} // ws
+} // hera
+
+// Serialization for tbb::concurrent_vector<...>
+namespace boost
+{
+ namespace serialization
+ {
+ template<class Archive, class T, class A>
+ void save(Archive& ar, const tbb::concurrent_vector<T,A>& v, const unsigned int file_version)
+ { stl::save_collection(ar, v); }
+
+ template<class Archive, class T, class A>
+ void load(Archive& ar, tbb::concurrent_vector<T,A>& v, const unsigned int file_version)
+ {
+ stl::load_collection<Archive,
+ tbb::concurrent_vector<T,A>,
+ stl::archive_input_seq< Archive, tbb::concurrent_vector<T,A> >,
+ stl::reserve_imp< tbb::concurrent_vector<T,A> >
+ >(ar, v);
+ }
+
+ template<class Archive, class T, class A>
+ void serialize(Archive& ar, tbb::concurrent_vector<T,A>& v, const unsigned int file_version)
+ { split_free(ar, v, file_version); }
+
+ template<class Archive, class T>
+ void save(Archive& ar, const tbb::atomic<T>& v, const unsigned int file_version)
+ { T v_ = v; ar << v_; }
+
+ template<class Archive, class T>
+ void load(Archive& ar, tbb::atomic<T>& v, const unsigned int file_version)
+ { T v_; ar >> v_; v = v_; }
+
+ template<class Archive, class T>
+ void serialize(Archive& ar, tbb::atomic<T>& v, const unsigned int file_version)
+ { split_free(ar, v, file_version); }
+ }
+}
+
+#else
+
+#include <algorithm>
+#include <map>
+
+namespace hera
+{
+namespace ws
+{
+namespace dnn
+{
+ template<class T>
+ struct vector
+ {
+ typedef ::std::vector<T> type;
+ };
+
+ template<class T>
+ struct atomic
+ {
+ typedef T type;
+ static T compare_and_swap(type& v, T n, T o) { if (v != o) return v; v = n; return o; }
+ };
+
+ template<class Iterator, class F>
+ void do_foreach(Iterator begin, Iterator end, const F& f) { std::for_each(begin, end, f); }
+
+ template<class F>
+ void for_each_range(size_t from, size_t to, const F& f)
+ {
+ for (size_t i = from; i < to; ++i)
+ f(i);
+ }
+
+ template<class Container, class F>
+ void for_each_range(Container& c, const F& f)
+ {
+ BOOST_FOREACH(const typename Container::value_type& i, c)
+ f(i);
+ }
+
+ template<class Container, class F>
+ void for_each_range(const Container& c, const F& f)
+ {
+ BOOST_FOREACH(const typename Container::value_type& i, c)
+ f(i);
+ }
+
+ struct mutex
+ {
+ struct scoped_lock
+ {
+ scoped_lock() {}
+ scoped_lock(mutex& ) {}
+ void acquire(mutex& ) const {}
+ void release() const {}
+ };
+ };
+
+ struct task_scheduler_init
+ {
+ task_scheduler_init(unsigned) {}
+ void initialize(unsigned) {}
+ static const unsigned automatic = 0;
+ static const unsigned deferred = 0;
+ };
+
+ struct task_group
+ {
+ template<class Functor>
+ void run(const Functor& f) const { f(); }
+ void wait() const {}
+ };
+
+ template<class ID, class NodePointer, class IDTraits, class Allocator>
+ struct map_traits
+ {
+ typedef std::map<ID, NodePointer,
+ typename IDTraits::Comparison,
+ Allocator> type;
+ typedef type range;
+ };
+
+} // dnn
+} // ws
+} // hera
+
+#endif // TBB
+
+namespace hera
+{
+namespace ws
+{
+namespace dnn
+{
+ template<class Range, class F>
+ void do_foreach(const Range& range, const F& f) { do_foreach(boost::begin(range), boost::end(range), f); }
+} // dnn
+} // ws
+} // hera
+
+#endif
diff --git a/wasserstein/include/dnn/parallel/utils.h b/wasserstein/include/dnn/parallel/utils.h
new file mode 100644
index 0000000..7104ec3
--- /dev/null
+++ b/wasserstein/include/dnn/parallel/utils.h
@@ -0,0 +1,100 @@
+#ifndef HERA_WS_PARALLEL_UTILS_H
+#define HERA_WS_PARALLEL_UTILS_H
+
+#include "../utils.h"
+
+namespace hera
+{
+namespace ws
+{
+namespace dnn
+{
+ // Assumes rng is synchronized across ranks
+ template<class DataVector, class RNGType, class SwapFunctor>
+ void shuffle(mpi::communicator& world, DataVector& data, RNGType& rng, const SwapFunctor& swap, DataVector empty = DataVector());
+
+ template<class DataVector, class RNGType>
+ void shuffle(mpi::communicator& world, DataVector& data, RNGType& rng)
+ {
+ typedef decltype(data[0]) T;
+ shuffle(world, data, rng, [](T& x, T& y) { std::swap(x,y); });
+ }
+} // dnn
+} // ws
+} // hera
+
+template<class DataVector, class RNGType, class SwapFunctor>
+void
+hera::ws::dnn::shuffle(mpi::communicator& world, DataVector& data, RNGType& rng, const SwapFunctor& swap, DataVector empty)
+{
+ // This is not a perfect shuffle: it dishes out data in chunks of 1/size.
+ // (It can be interpreted as generating a bistochastic matrix by taking the
+ // sum of size random permutation matrices.) Hopefully, it works for our purposes.
+
+ typedef typename RNGType::result_type RNGResult;
+
+ int size = world.size();
+ int rank = world.rank();
+
+ // Generate local seeds
+ boost::uniform_int<RNGResult> uniform;
+ RNGResult seed;
+ for (size_t i = 0; i < size; ++i)
+ {
+ RNGResult v = uniform(rng);
+ if (i == rank)
+ seed = v;
+ }
+ RNGType local_rng(seed);
+
+ // Shuffle local data
+ hera::ws::dnn::random_shuffle(data.begin(), data.end(), local_rng, swap);
+
+ // Decide how much of our data goes to i-th processor
+ std::vector<size_t> out_counts(size);
+ std::vector<int> ranks(boost::counting_iterator<int>(0),
+ boost::counting_iterator<int>(size));
+ for (size_t i = 0; i < size; ++i)
+ {
+ hera::ws::dnn::random_shuffle(ranks.begin(), ranks.end(), rng);
+ ++out_counts[ranks[rank]];
+ }
+
+ // Fill the outgoing array
+ size_t total = 0;
+ std::vector< DataVector > outgoing(size, empty);
+ for (size_t i = 0; i < size; ++i)
+ {
+ size_t count = data.size()*out_counts[i]/size;
+ if (total + count > data.size())
+ count = data.size() - total;
+
+ outgoing[i].reserve(count);
+ for (size_t j = total; j < total + count; ++j)
+ outgoing[i].push_back(data[j]);
+
+ total += count;
+ }
+
+ boost::uniform_int<size_t> uniform_outgoing(0,size-1); // in range [0,size-1]
+ while(total < data.size()) // send leftover to random processes
+ {
+ outgoing[uniform_outgoing(local_rng)].push_back(data[total]);
+ ++total;
+ }
+ data.clear();
+
+ // Exchange the data
+ std::vector< DataVector > incoming(size, empty);
+ mpi::all_to_all(world, outgoing, incoming);
+ outgoing.clear();
+
+ // Assemble our data
+ for(const DataVector& vec : incoming)
+ for (size_t i = 0; i < vec.size(); ++i)
+ data.push_back(vec[i]);
+ hera::ws::dnn::random_shuffle(data.begin(), data.end(), local_rng, swap);
+ // XXX: the final shuffle is irrelevant for our purposes. But it's also cheap.
+}
+
+#endif
diff --git a/wasserstein/include/dnn/utils.h b/wasserstein/include/dnn/utils.h
new file mode 100644
index 0000000..bbce793
--- /dev/null
+++ b/wasserstein/include/dnn/utils.h
@@ -0,0 +1,47 @@
+#ifndef HERA_WS_DNN_UTILS_H
+#define HERA_WS_DNN_UTILS_H
+
+#include <boost/random/uniform_int.hpp>
+#include <boost/foreach.hpp>
+#include <boost/typeof/typeof.hpp>
+
+namespace hera
+{
+namespace ws
+{
+namespace dnn
+{
+
+template <typename T, typename... Args>
+struct has_coordinates
+{
+ template <typename C, typename = decltype( std::declval<C>().coordinate(std::declval<Args>()...) )>
+ static std::true_type test(int);
+
+ template <typename C>
+ static std::false_type test(...);
+
+ static constexpr bool value = decltype(test<T>(0))::value;
+};
+
+template<class RandomIt, class UniformRandomNumberGenerator, class SwapFunctor>
+void random_shuffle(RandomIt first, RandomIt last, UniformRandomNumberGenerator& g, const SwapFunctor& swap)
+{
+ size_t n = last - first;
+ boost::uniform_int<size_t> uniform(0,n);
+ for (size_t i = n-1; i > 0; --i)
+ swap(first[i], first[uniform(g,i+1)]); // picks a random number in [0,i] range
+}
+
+template<class RandomIt, class UniformRandomNumberGenerator>
+void random_shuffle(RandomIt first, RandomIt last, UniformRandomNumberGenerator& g)
+{
+ typedef decltype(*first) T;
+ random_shuffle(first, last, g, [](T& x, T& y) { std::swap(x,y); });
+}
+
+} // dnn
+} // ws
+} // hera
+
+#endif
diff --git a/wasserstein/include/hera_infinity.h b/wasserstein/include/hera_infinity.h
new file mode 100644
index 0000000..8d86dbb
--- /dev/null
+++ b/wasserstein/include/hera_infinity.h
@@ -0,0 +1,22 @@
+#ifndef WASSERSTEIN_HERA_INFINITY_H
+#define WASSERSTEIN_HERA_INFINITY_H
+
+// we cannot assume that template parameter Real will always provide infinity() value,
+// so value -1.0 is used to encode infinity (l_inf norm is used by default)
+
+namespace hera {
+
+ template<class Real = double>
+ inline bool is_infinity(const Real& x)
+ {
+ return x == Real(-1);
+ };
+
+ template<class Real = double>
+ inline constexpr Real get_infinity()
+ {
+ return Real(-1);
+ }
+}
+
+#endif //WASSERSTEIN_HERA_INFINITY_H
diff --git a/wasserstein/include/opts/opts.h b/wasserstein/include/opts/opts.h
new file mode 100755
index 0000000..74e788b
--- /dev/null
+++ b/wasserstein/include/opts/opts.h
@@ -0,0 +1,353 @@
+/**
+ * Author: Dmitriy Morozov <dmitriy@mrzv.org>
+ * The interface is heavily influenced by GetOptPP (https://code.google.com/p/getoptpp/).
+ */
+
+#ifndef OPTS_OPTS_H
+#define OPTS_OPTS_H
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <list>
+#include <vector>
+
+namespace opts {
+
+// Converters
+template<class T>
+struct Converter
+{
+ Converter() {}
+ static
+ T convert(const std::string& val) { std::istringstream iss(val); T res; iss >> res; return res; }
+};
+
+// Type
+template<class T>
+struct Traits
+{
+ static std::string type_string() { return "UNKNOWN TYPE"; }
+};
+
+template<>
+struct Traits<int>
+{
+ static std::string type_string() { return "INT"; }
+};
+
+template<>
+struct Traits<short int>
+{
+ static std::string type_string() { return "SHORT INT"; }
+};
+
+template<>
+struct Traits<unsigned>
+{
+ static std::string type_string() { return "UNSIGNED INT"; }
+};
+
+template<>
+struct Traits<short unsigned>
+{
+ static std::string type_string() { return "SHORT UNSIGNED INT"; }
+};
+
+template<>
+struct Traits<float>
+{
+ static std::string type_string() { return "FLOAT"; }
+};
+
+template<>
+struct Traits<double>
+{
+ static std::string type_string() { return "DOUBLE"; }
+};
+
+template<>
+struct Traits<std::string>
+{
+ static std::string type_string() { return "STRING"; }
+};
+
+
+struct BasicOption
+{
+ BasicOption(char s_,
+ std::string l_,
+ std::string default_,
+ std::string type_,
+ std::string help_):
+ s(s_), l(l_), d(default_), t(type_), help(help_) {}
+
+ int long_size() const { return l.size() + 1 + t.size(); }
+
+ void output(std::ostream& out, int max_long) const
+ {
+ out << " ";
+ if (s)
+ out << '-' << s << ", ";
+ else
+ out << " ";
+
+ out << "--" << l << ' ';
+
+ if (!t.empty())
+ out << t;
+
+ for (int i = long_size(); i < max_long; ++i)
+ out << ' ';
+
+ out << " " << help;
+
+ if (!d.empty())
+ {
+ out << " [default: " << d << "]";
+ }
+ out << '\n';
+ }
+
+ char s;
+ std::string l;
+ std::string d;
+ std::string t;
+ std::string help;
+};
+
+// Option
+template<class T>
+struct OptionContainer: public BasicOption
+{
+ OptionContainer(char s_,
+ const std::string& l_,
+ T& var_,
+ const std::string& help_,
+ const std::string& type_ = Traits<T>::type_string()):
+ BasicOption(s_, l_, default_value(var_), type_, help_),
+ var(&var_) {}
+
+ static
+ std::string default_value(const T& def)
+ {
+ std::ostringstream oss;
+ oss << def;
+ return oss.str();
+ }
+
+ void parse(std::list<std::string>& args) const
+ {
+ std::string short_opt = "-"; short_opt += s;
+ std::string long_opt = "--" + l;
+ for (std::list<std::string>::iterator cur = args.begin(); cur != args.end(); ++cur)
+ {
+ if (*cur == short_opt || *cur == long_opt)
+ {
+ cur = args.erase(cur);
+ if (cur != args.end())
+ {
+ *var = Converter<T>::convert(*cur);
+ cur = args.erase(cur);
+ break; // finds first occurrence
+ }
+ else
+ break; // if the last option's value is missing, it remains default
+
+ }
+ }
+ }
+
+ T* var;
+};
+
+template<class T>
+struct OptionContainer< std::vector<T> >: public BasicOption
+{
+ OptionContainer(char s_,
+ const std::string& l_,
+ std::vector<T>& var_,
+ const std::string& help_,
+ const std::string& type_ = "SEQUENCE"):
+ BasicOption(s_, l_, default_value(var_), type_, help_),
+ var(&var_) { }
+
+ static
+ std::string default_value(const std::vector<T>& def)
+ {
+ std::ostringstream oss;
+ oss << "(";
+ if (def.size())
+ oss << def[0];
+ for (int i = 1; i < def.size(); ++i)
+ oss << ", " << def[i];
+ oss << ")";
+ return oss.str();
+ }
+
+ void parse(std::list<std::string>& args) const
+ {
+ std::string short_opt = "-"; short_opt += s;
+ std::string long_opt = "--" + l;
+ for (std::list<std::string>::iterator cur = args.begin(); cur != args.end(); ++cur)
+ {
+ if (*cur == short_opt || *cur == long_opt)
+ {
+ cur = args.erase(cur);
+ if (cur != args.end())
+ {
+ var->push_back(Converter<T>::convert(*cur));
+ cur = args.erase(cur);
+ }
+ --cur;
+ }
+ }
+ }
+
+ std::vector<T>* var;
+};
+
+
+template<class T>
+OptionContainer<T>
+Option(char s, const std::string& l, T& var, const std::string& help) { return OptionContainer<T>(s, l, var, help); }
+
+template<class T>
+OptionContainer<T>
+Option(char s, const std::string& l, T& var,
+ const std::string& type, const std::string& help) { return OptionContainer<T>(s, l, var, help, type); }
+
+template<class T>
+OptionContainer<T>
+Option(const std::string& l, T& var, const std::string& help) { return OptionContainer<T>(0, l, var, help); }
+
+template<class T>
+OptionContainer<T>
+Option(const std::string& l, T& var,
+ const std::string& type, const std::string& help) { return OptionContainer<T>(0, l, var, help, type); }
+
+// Present
+struct PresentContainer: public BasicOption
+{
+ PresentContainer(char s, const std::string& l, const std::string& help):
+ BasicOption(s,l,"","",help) {}
+};
+
+inline
+PresentContainer
+Present(char s, const std::string& l, const std::string& help) { return PresentContainer(s, l, help); }
+
+inline
+PresentContainer
+Present(const std::string& l, const std::string& help) { return PresentContainer(0, l, help); }
+
+// PosOption
+template<class T>
+struct PosOptionContainer
+{
+ PosOptionContainer(T& var_):
+ var(&var_) {}
+
+ bool parse(std::list<std::string>& args) const
+ {
+ if (args.empty())
+ return false;
+
+ *var = Converter<T>::convert(args.front());
+ args.pop_front();
+ return true;
+ }
+
+ T* var;
+};
+
+template<class T>
+PosOptionContainer<T>
+PosOption(T& var) { return PosOptionContainer<T>(var); }
+
+
+// Options
+struct Options
+{
+ Options(int argc_, char** argv_):
+ args(argv_ + 1, argv_ + argc_),
+ failed(false) {}
+
+ template<class T>
+ Options& operator>>(const OptionContainer<T>& oc);
+ bool operator>>(const PresentContainer& pc);
+ template<class T>
+ Options& operator>>(const PosOptionContainer<T>& poc);
+
+ operator bool() { return !failed; }
+
+
+ friend
+ std::ostream&
+ operator<<(std::ostream& out, const Options& ops)
+ {
+ int max_long = 0;
+ for (std::list<BasicOption>::const_iterator cur = ops.options.begin();
+ cur != ops.options.end();
+ ++cur)
+ {
+ int cur_long = cur->long_size();
+ if (cur_long > max_long)
+ max_long = cur_long;
+ }
+
+ out << "Options:\n";
+ for (std::list<BasicOption>::const_iterator cur = ops.options.begin();
+ cur != ops.options.end();
+ ++cur)
+ cur->output(out, max_long);
+
+ return out;
+ }
+
+
+ private:
+ std::list<std::string> args;
+ std::list<BasicOption> options;
+ bool failed;
+};
+
+template<class T>
+Options&
+Options::operator>>(const OptionContainer<T>& oc)
+{
+ options.push_back(oc);
+ oc.parse(args);
+ return *this;
+}
+
+inline
+bool
+Options::operator>>(const PresentContainer& pc)
+{
+ options.push_back(pc);
+
+ for(std::list<std::string>::iterator cur = args.begin(); cur != args.end(); ++cur)
+ {
+ std::string short_opt = "-"; short_opt += pc.s;
+ std::string long_opt = "--" + pc.l;
+ if (*cur == short_opt || *cur == long_opt)
+ {
+ args.erase(cur);
+ return true;
+ }
+ }
+ return false;
+}
+
+template<class T>
+Options&
+Options::operator>>(const PosOptionContainer<T>& poc)
+{
+ failed = !poc.parse(args);
+ return *this;
+}
+
+}
+
+#endif
diff --git a/wasserstein/include/wasserstein.h b/wasserstein/include/wasserstein.h
new file mode 100644
index 0000000..db6ce11
--- /dev/null
+++ b/wasserstein/include/wasserstein.h
@@ -0,0 +1,346 @@
+/*
+
+Copyright (c) 2015, M. Kerber, D. Morozov, A. Nigmetov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+You are under no obligation whatsoever to provide any bug fixes, patches, or
+upgrades to the features, functionality or performance of the source code
+(Enhancements) to anyone; however, if you choose to make your Enhancements
+available either publicly, or directly to copyright holder,
+without imposing a separate written license agreement for such Enhancements,
+then you hereby grant the following license: a non-exclusive, royalty-free
+perpetual license to install, use, modify, prepare derivative works, incorporate
+into other computer software, distribute, and sublicense such enhancements or
+derivative works thereof, in binary and source code form.
+
+ */
+
+#ifndef HERA_WASSERSTEIN_H
+#define HERA_WASSERSTEIN_H
+
+#include <vector>
+#include <map>
+#include <math.h>
+
+#include "def_debug_ws.h"
+#include "basic_defs_ws.h"
+#include "diagram_reader.h"
+#include "auction_runner_gs.h"
+#include "auction_runner_gs_single_diag.h"
+#include "auction_runner_jac.h"
+#include "auction_runner_fr.h"
+
+
+namespace hera
+{
+
+template<class PairContainer_, class PointType_ = typename std::remove_reference< decltype(*std::declval<PairContainer_>().begin())>::type >
+struct DiagramTraits
+{
+ using PointType = PointType_;
+ using RealType = typename std::remove_reference< decltype(std::declval<PointType>()[0]) >::type;
+
+ static RealType get_x(const PointType& p) { return p[0]; }
+ static RealType get_y(const PointType& p) { return p[1]; }
+};
+
+template<class PairContainer_, class RealType_>
+struct DiagramTraits<PairContainer_, std::pair<RealType_, RealType_>>
+{
+ using RealType = RealType_;
+ using PointType = std::pair<RealType, RealType>;
+
+ static RealType get_x(const PointType& p) { return p.first; }
+ static RealType get_y(const PointType& p) { return p.second; }
+};
+
+
+namespace ws
+{
+
+ // compare as multisets
+ template<class PairContainer>
+ inline bool are_equal(const PairContainer& dgm1, const PairContainer& dgm2)
+ {
+ if (dgm1.size() != dgm2.size()) {
+ return false;
+ }
+
+ using Traits = typename hera::DiagramTraits<PairContainer>;
+ using PointType = typename Traits::PointType;
+
+ std::map<PointType, int> m1, m2;
+
+ for(auto&& pair1 : dgm1) {
+ m1[pair1]++;
+ }
+
+ for(auto&& pair2 : dgm2) {
+ m2[pair2]++;
+ }
+
+ return m1 == m2;
+ }
+
+ // to handle points with one coordinate = infinity
+ template<class RealType>
+ inline RealType get_one_dimensional_cost(std::vector<RealType>& set_A,
+ std::vector<RealType>& set_B,
+ const RealType wasserstein_power)
+ {
+ if (set_A.size() != set_B.size()) {
+ return std::numeric_limits<RealType>::infinity();
+ }
+ std::sort(set_A.begin(), set_A.end());
+ std::sort(set_B.begin(), set_B.end());
+ RealType result = 0.0;
+ for(size_t i = 0; i < set_A.size(); ++i) {
+ result += std::pow(std::fabs(set_A[i] - set_B[i]), wasserstein_power);
+ }
+ return result;
+ }
+
+
+ template<class RealType>
+ struct SplitProblemInput
+ {
+ std::vector<DiagramPoint<RealType>> A_1;
+ std::vector<DiagramPoint<RealType>> B_1;
+ std::vector<DiagramPoint<RealType>> A_2;
+ std::vector<DiagramPoint<RealType>> B_2;
+
+ std::unordered_map<size_t, size_t> A_1_indices;
+ std::unordered_map<size_t, size_t> A_2_indices;
+ std::unordered_map<size_t, size_t> B_1_indices;
+ std::unordered_map<size_t, size_t> B_2_indices;
+
+ RealType mid_coord { 0.0 };
+ RealType strip_width { 0.0 };
+
+ void init_vectors(size_t n)
+ {
+
+ A_1_indices.clear();
+ A_2_indices.clear();
+ B_1_indices.clear();
+ B_2_indices.clear();
+
+ A_1.clear();
+ A_2.clear();
+ B_1.clear();
+ B_2.clear();
+
+ A_1.reserve(n / 2);
+ B_1.reserve(n / 2);
+ A_2.reserve(n / 2);
+ B_2.reserve(n / 2);
+ }
+
+ void init(const std::vector<DiagramPoint<RealType>>& A,
+ const std::vector<DiagramPoint<RealType>>& B)
+ {
+ using DiagramPointR = DiagramPoint<RealType>;
+
+ init_vectors(A.size());
+
+ RealType min_sum = std::numeric_limits<RealType>::max();
+ RealType max_sum = -std::numeric_limits<RealType>::max();
+ for(const auto& p_A : A) {
+ RealType s = p_A[0] + p_A[1];
+ if (s > max_sum)
+ max_sum = s;
+ if (s < min_sum)
+ min_sum = s;
+ mid_coord += s;
+ }
+
+ mid_coord /= A.size();
+
+ strip_width = 0.25 * (max_sum - min_sum);
+
+ auto first_diag_iter = std::upper_bound(A.begin(), A.end(), 0, [](const int& a, const DiagramPointR& p) { return a < (int)(p.is_diagonal()); });
+ size_t num_normal_A_points = std::distance(A.begin(), first_diag_iter);
+
+ // process all normal points in A,
+ // projections follow normal points
+ for(size_t i = 0; i < A.size(); ++i) {
+
+ assert(i < num_normal_A_points and A.is_normal() or i >= num_normal_A_points and A.is_diagonal());
+ assert(i < num_normal_A_points and B.is_diagonal() or i >= num_normal_A_points and B.is_normal());
+
+ RealType s = i < num_normal_A_points ? A[i][0] + A[i][1] : B[i][0] + B[i][1];
+
+ if (s < mid_coord + strip_width) {
+ // add normal point and its projection to the
+ // left half
+ A_1.push_back(A[i]);
+ B_1.push_back(B[i]);
+ A_1_indices[i] = A_1.size() - 1;
+ B_1_indices[i] = B_1.size() - 1;
+ }
+
+ if (s > mid_coord - strip_width) {
+ // to the right half
+ A_2.push_back(A[i]);
+ B_2.push_back(B[i]);
+ A_2_indices[i] = A_2.size() - 1;
+ B_2_indices[i] = B_2.size() - 1;
+ }
+
+ }
+ } // end init
+
+ };
+
+
+ // CAUTION:
+ // this function assumes that all coordinates are finite
+ // points at infinity are processed in wasserstein_cost
+ template<class RealType>
+ inline RealType wasserstein_cost_vec(const std::vector<DiagramPoint<RealType>>& A,
+ const std::vector<DiagramPoint<RealType>>& B,
+ AuctionParams<RealType>& params,
+ const std::string& _log_filename_prefix)
+ {
+ if (params.wasserstein_power < 1.0) {
+ throw std::runtime_error("Bad q in Wasserstein " + std::to_string(params.wasserstein_power));
+ }
+ if (params.delta < 0.0) {
+ throw std::runtime_error("Bad delta in Wasserstein " + std::to_string(params.delta));
+ }
+ if (params.initial_epsilon < 0.0) {
+ throw std::runtime_error("Bad initial epsilon in Wasserstein" + std::to_string(params.initial_epsilon));
+ }
+ if (params.epsilon_common_ratio < 0.0) {
+ throw std::runtime_error("Bad epsilon factor in Wasserstein " + std::to_string(params.epsilon_common_ratio));
+ }
+
+ if (A.empty() and B.empty())
+ return 0.0;
+
+ RealType result;
+
+ // just use Gauss-Seidel
+ AuctionRunnerGS<RealType> auction(A, B, params, _log_filename_prefix);
+ auction.run_auction();
+ result = auction.get_wasserstein_cost();
+ params.final_relative_error = auction.get_relative_error();
+ return result;
+ }
+
+} // ws
+
+
+
+template<class PairContainer>
+inline typename DiagramTraits<PairContainer>::RealType
+wasserstein_cost(const PairContainer& A,
+ const PairContainer& B,
+ AuctionParams< typename DiagramTraits<PairContainer>::RealType >& params,
+ const std::string& _log_filename_prefix = "")
+{
+ using Traits = DiagramTraits<PairContainer>;
+
+ //using PointType = typename Traits::PointType;
+ using RealType = typename Traits::RealType;
+
+ if (hera::ws::are_equal(A, B)) {
+ return 0.0;
+ }
+
+ bool a_empty = true;
+ bool b_empty = true;
+ RealType total_cost_A = 0.0;
+ RealType total_cost_B = 0.0;
+
+ using DgmPoint = hera::ws::DiagramPoint<RealType>;
+
+ std::vector<DgmPoint> dgm_A, dgm_B;
+ // coordinates of points at infinity
+ std::vector<RealType> x_plus_A, x_minus_A, y_plus_A, y_minus_A;
+ std::vector<RealType> x_plus_B, x_minus_B, y_plus_B, y_minus_B;
+ // loop over A, add projections of A-points to corresponding positions
+ // in B-vector
+ for(auto&& pair_A : A) {
+ a_empty = false;
+ RealType x = Traits::get_x(pair_A);
+ RealType y = Traits::get_y(pair_A);
+ if ( x == std::numeric_limits<RealType>::infinity()) {
+ y_plus_A.push_back(y);
+ } else if (x == -std::numeric_limits<RealType>::infinity()) {
+ y_minus_A.push_back(y);
+ } else if (y == std::numeric_limits<RealType>::infinity()) {
+ x_plus_A.push_back(x);
+ } else if (y == -std::numeric_limits<RealType>::infinity()) {
+ x_minus_A.push_back(x);
+ } else {
+ dgm_A.emplace_back(x, y, DgmPoint::NORMAL);
+ dgm_B.emplace_back(x, y, DgmPoint::DIAG);
+ total_cost_A += std::pow(dgm_A.back().persistence_lp(params.internal_p), params.wasserstein_power);
+ }
+ }
+ // the same for B
+ for(auto&& pair_B : B) {
+ b_empty = false;
+ RealType x = Traits::get_x(pair_B);
+ RealType y = Traits::get_y(pair_B);
+ if (x == std::numeric_limits<RealType>::infinity()) {
+ y_plus_B.push_back(y);
+ } else if (x == -std::numeric_limits<RealType>::infinity()) {
+ y_minus_B.push_back(y);
+ } else if (y == std::numeric_limits<RealType>::infinity()) {
+ x_plus_B.push_back(x);
+ } else if (y == -std::numeric_limits<RealType>::infinity()) {
+ x_minus_B.push_back(x);
+ } else {
+ dgm_A.emplace_back(x, y, DgmPoint::DIAG);
+ dgm_B.emplace_back(x, y, DgmPoint::NORMAL);
+ total_cost_B += std::pow(dgm_B.back().persistence_lp(params.internal_p), params.wasserstein_power);
+ }
+ }
+
+ RealType infinity_cost = ws::get_one_dimensional_cost(x_plus_A, x_plus_B, params.wasserstein_power);
+ infinity_cost += ws::get_one_dimensional_cost(x_minus_A, x_minus_B, params.wasserstein_power);
+ infinity_cost += ws::get_one_dimensional_cost(y_plus_A, y_plus_B, params.wasserstein_power);
+ infinity_cost += ws::get_one_dimensional_cost(y_minus_A, y_minus_B, params.wasserstein_power);
+
+ if (a_empty)
+ return total_cost_B + infinity_cost;
+
+ if (b_empty)
+ return total_cost_A + infinity_cost;
+
+
+ if (infinity_cost == std::numeric_limits<RealType>::infinity()) {
+ return infinity_cost;
+ } else {
+ return infinity_cost + wasserstein_cost_vec(dgm_A, dgm_B, params, _log_filename_prefix);
+ }
+
+}
+
+template<class PairContainer>
+inline typename DiagramTraits<PairContainer>::RealType
+wasserstein_dist(const PairContainer& A,
+ const PairContainer& B,
+ AuctionParams<typename DiagramTraits<PairContainer>::RealType>& params,
+ const std::string& _log_filename_prefix = "")
+{
+ using Real = typename DiagramTraits<PairContainer>::RealType;
+ return std::pow(hera::wasserstein_cost(A, B, params, _log_filename_prefix), Real(1.)/params.wasserstein_power);
+}
+
+} // end of namespace hera
+
+#endif
diff --git a/wasserstein/include/wasserstein_pure_geom.hpp b/wasserstein/include/wasserstein_pure_geom.hpp
new file mode 100644
index 0000000..096d95d
--- /dev/null
+++ b/wasserstein/include/wasserstein_pure_geom.hpp
@@ -0,0 +1,86 @@
+#ifndef WASSERSTEIN_PURE_GEOM_HPP
+#define WASSERSTEIN_PURE_GEOM_HPP
+
+#define WASSERSTEIN_PURE_GEOM
+
+
+#include "diagram_reader.h"
+#include "auction_oracle_kdtree_pure_geom.h"
+#include "auction_runner_gs.h"
+#include "auction_runner_jac.h"
+
+namespace hera
+{
+namespace ws
+{
+
+ template <class Real>
+ using DynamicTraits = typename hera::ws::dnn::DynamicPointTraits<Real>;
+
+ template <class Real>
+ using DynamicPoint = typename hera::ws::dnn::DynamicPointTraits<Real>::PointType;
+
+ template <class Real>
+ using DynamicPointVector = typename hera::ws::dnn::DynamicPointVector<Real>;
+
+ template <class Real>
+ using AuctionRunnerGSR = typename hera::ws::AuctionRunnerGS<Real, hera::ws::AuctionOracleKDTreePureGeom<Real>, hera::ws::dnn::DynamicPointVector<Real>>;
+
+ template <class Real>
+ using AuctionRunnerJacR = typename hera::ws::AuctionRunnerJac<Real, hera::ws::AuctionOracleKDTreePureGeom<Real>, hera::ws::dnn::DynamicPointVector<Real>>;
+
+
+inline double wasserstein_cost(const DynamicPointVector<double>& set_A, const DynamicPointVector<double>& set_B, const AuctionParams<double>& params)
+{
+ if (params.wasserstein_power < 1.0) {
+ throw std::runtime_error("Bad q in Wasserstein " + std::to_string(params.wasserstein_power));
+ }
+
+ if (params.delta < 0.0) {
+ throw std::runtime_error("Bad delta in Wasserstein " + std::to_string(params.delta));
+ }
+
+ if (params.initial_epsilon < 0.0) {
+ throw std::runtime_error("Bad initial epsilon in Wasserstein" + std::to_string(params.initial_epsilon));
+ }
+
+ if (params.epsilon_common_ratio < 0.0) {
+ throw std::runtime_error("Bad epsilon factor in Wasserstein " + std::to_string(params.epsilon_common_ratio));
+ }
+
+ if (set_A.size() != set_B.size()) {
+ throw std::runtime_error("Different cardinalities of point clouds: " + std::to_string(set_A.size()) + " != " + std::to_string(set_B.size()));
+ }
+
+ DynamicTraits<double> traits(params.dim);
+
+ DynamicPointVector<double> set_A_copy(set_A);
+ DynamicPointVector<double> set_B_copy(set_B);
+
+ // set point id to the index in vector
+ for(size_t i = 0; i < set_A.size(); ++i) {
+ traits.id(set_A_copy[i]) = i;
+ traits.id(set_B_copy[i]) = i;
+ }
+
+ if (params.max_bids_per_round == 1) {
+ hera::ws::AuctionRunnerGSR<double> auction(set_A_copy, set_B_copy, params);
+ auction.run_auction();
+ return auction.get_wasserstein_cost();
+ } else {
+ hera::ws::AuctionRunnerJacR<double> auction(set_A_copy, set_B_copy, params);
+ auction.run_auction();
+ return auction.get_wasserstein_cost();
+ }
+}
+
+inline double wasserstein_dist(const DynamicPointVector<double>& set_A, const DynamicPointVector<double>& set_B, const AuctionParams<double>& params)
+{
+ return std::pow(wasserstein_cost(set_A, set_B, params), 1.0 / params.wasserstein_power);
+}
+
+} // ws
+} // hera
+
+
+#endif
diff --git a/wasserstein/tests/data/test_100_A b/wasserstein/tests/data/test_100_A
new file mode 100644
index 0000000..8d126f0
--- /dev/null
+++ b/wasserstein/tests/data/test_100_A
@@ -0,0 +1,100 @@
+7.50638 7.78005
+0.991758 2.12178
+5.18481 6.61702
+6.14703 7.08581
+4.09936 4.83024
+3.79915 4.51283
+3.17645 3.75321
+0.61305 0.998622
+0.445643 1.13781
+6.38205 6.53669
+5.96392 6.44093
+7.21047 7.26005
+0.6703 1.26593
+0.529933 1.7027
+7.92495 8.83023
+2.1382 2.71695
+3.79209 4.5197
+5.23354 5.82214
+-0.395097 2.18831
+3.22028 3.88648
+5.56262 5.79949
+8.39623 9.37185
+2.7452 3.84539
+9.5022 10.2414
+1.01374 1.40504
+3.2029 3.89559
+7.61236 8.28485
+6.4371 6.909
+4.45616 5.35067
+1.57802 1.77895
+6.5991 7.76339
+6.66729 6.71714
+6.11898 6.57121
+2.60663 4.36396
+-0.259613 1.17683
+7.72857 9.48862
+4.68398 5.51521
+4.87447 5.4233
+6.86301 6.88244
+4.17814 4.25886
+8.70558 9.72902
+4.40873 4.57389
+6.1824 7.05049
+7.97557 8.79739
+8.52591 8.6985
+5.15336 5.27796
+9.70144 9.77031
+0.561778 1.39045
+9.32553 10.2456
+7.01495 7.74521
+6.83355 7.28255
+1.96721 3.01504
+5.78411 7.59464
+5.64012 6.10721
+3.7249 5.17086
+4.33297 5.91657
+7.11793 7.2545
+5.109 6.76878
+3.02787 3.04077
+0.999365 2.05566
+8.81392 8.9086
+6.20106 6.78943
+6.7987 7.05794
+0.438805 0.449602
+8.71793 9.79853
+-0.150282 0.51997
+5.72257 5.93156
+5.71098 6.09535
+9.0378 9.45942
+0.534987 0.872885
+7.72276 8.57754
+9.26069 9.40289
+4.148 4.80519
+1.04579 3.18109
+0.259767 0.93215
+0.250608 0.511569
+4.88108 5.62239
+4.6731 5.3348
+7.84979 7.93545
+0.912521 1.48142
+4.82553 5.38108
+6.02179 7.61665
+3.85848 6.39418
+5.10754 6.02118
+1.71956 1.86238
+6.47336 6.74034
+-0.0371018 0.212738
+3.97259 4.15465
+2.17413 3.20188
+4.49098 6.09812
+6.62445 7.84196
+6.57541 7.432
+6.81052 9.6653
+3.67502 4.69734
+3.92378 4.14743
+5.93127 6.46154
+0.63424 0.705454
+7.60129 9.23263
+4.23064 4.74575
+0.397705 1.24458
diff --git a/wasserstein/tests/data/test_100_A.pd.dipha b/wasserstein/tests/data/test_100_A.pd.dipha
new file mode 100644
index 0000000..e94f5fe
--- /dev/null
+++ b/wasserstein/tests/data/test_100_A.pd.dipha
Binary files differ
diff --git a/wasserstein/tests/data/test_100_B b/wasserstein/tests/data/test_100_B
new file mode 100644
index 0000000..852799d
--- /dev/null
+++ b/wasserstein/tests/data/test_100_B
@@ -0,0 +1,100 @@
+5.8232 6.36308
+2.16066 2.48668
+2.38754 4.91418
+4.77403 5.43982
+0.291412 1.11147
+3.77337 5.2686
+8.31344 9.05384
+0.734064 1.14844
+7.57606 7.8521
+3.16719 3.86953
+2.55072 2.64932
+9.51707 9.6071
+0.304643 2.41784
+2.79925 3.28234
+5.32901 7.7576
+5.19903 6.30449
+1.87819 2.99454
+8.92272 9.67105
+4.62414 5.05592
+4.0079 4.64148
+2.26369 3.44573
+2.69335 3.13426
+1.90706 2.42652
+2.68113 2.79133
+1.41065 1.56018
+6.55282 7.18725
+5.72986 6.37151
+7.26968 8.22623
+3.32643 3.73606
+3.77325 4.63115
+1.05457 1.83651
+8.6815 8.85251
+3.91285 4.17139
+0.380936 0.842109
+7.33227 7.69334
+8.45635 8.923
+4.1769 5.08373
+0.501374 2.23328
+-0.161782 1.28908
+3.44716 3.4662
+3.15394 4.30243
+8.71416 9.3781
+6.3034 8.62893
+6.53824 7.04611
+0.6386 1.35269
+0.862088 0.960371
+5.12963 5.20203
+1.58695 2.0452
+6.57698 6.63228
+3.87747 4.45669
+1.51273 3.25669
+-0.0992804 0.667302
+4.7489 4.80059
+0.0280559 1.90471
+6.7462 8.27612
+0.915652 1.30007
+2.79556 3.77404
+9.87989 10.0722
+9.39105 9.84229
+7.57235 9.37122
+5.09426 6.44266
+6.3994 6.72037
+5.73441 6.99341
+6.9079 7.88049
+4.2003 4.41933
+-1.72447 2.25877
+9.04907 9.64323
+4.40473 5.3593
+9.31201 9.96079
+7.28343 8.74163
+3.0172 6.23779
+8.08422 8.56069
+6.83038 6.99863
+2.32038 3.1289
+7.42302 8.26286
+6.66905 7.18496
+0.730748 1.61335
+4.00564 5.73993
+2.81231 3.67489
+2.33178 2.37845
+9.03302 9.68681
+0.567816 0.755485
+7.89783 8.7621
+0.177662 0.332833
+-0.181569 1.36821
+6.22158 6.55787
+4.67115 5.16995
+0.806432 0.820738
+7.69636 7.87402
+4.40933 4.54995
+9.1329 9.15037
+8.87416 9.04329
+1.14349 1.8993
+3.29756 4.7172
+6.67873 8.31364
+6.91238 7.1654
+0.483084 1.55006
+2.66058 3.86294
+5.93347 6.06085
+7.40514 9.05071
diff --git a/wasserstein/tests/data/test_100_B.pd.dipha b/wasserstein/tests/data/test_100_B.pd.dipha
new file mode 100644
index 0000000..25d6734
--- /dev/null
+++ b/wasserstein/tests/data/test_100_B.pd.dipha
Binary files differ
diff --git a/wasserstein/tests/data/test_200_A b/wasserstein/tests/data/test_200_A
new file mode 100644
index 0000000..164b71d
--- /dev/null
+++ b/wasserstein/tests/data/test_200_A
@@ -0,0 +1,200 @@
+0.471299 1.89241
+2.82136 3.97846
+8.81923 9.20678
+1.42474 1.65425
+8.36963 9.16097
+-0.236476 0.692489
+7.57182 8.06148
+2.89878 3.21958
+7.1285 7.51707
+5.75496 7.09461
+6.00081 6.10914
+9.60869 9.64676
+7.42889 8.97174
+7.26061 8.55944
+2.41226 2.5146
+8.5616 9.44847
+7.4946 8.86962
+5.42244 6.98028
+9.62386 9.96039
+7.70591 9.92849
+1.34119 3.2048
+3.92169 5.15228
+8.82955 9.60318
+7.94213 9.39997
+2.6716 4.02057
+0.375206 0.497663
+1.94572 3.65599
+1.03366 1.46356
+8.91855 10.1838
+7.11087 8.64425
+2.63266 2.78706
+8.93611 10.2943
+8.51999 9.28356
+1.31436 3.13725
+1.92871 4.00178
+8.30503 8.45555
+2.58739 2.82076
+3.20419 5.29453
+7.4015 8.13225
+9.07991 9.74729
+0.822366 0.938371
+2.90508 4.29367
+4.32385 5.4787
+3.63054 4.6918
+8.52962 9.87004
+1.16994 2.39465
+2.61903 3.33772
+4.15505 4.52942
+8.7068 9.66579
+8.10373 9.31351
+0.7954 1.23001
+7.82253 8.69505
+4.59616 5.91996
+1.02032 1.93931
+6.98421 8.46017
+8.42263 11.3447
+2.63444 3.7158
+7.49059 9.1137
+-0.122109 1.41074
+8.29578 8.81161
+6.24793 6.32368
+4.07212 4.39695
+5.32453 7.457
+8.3892 9.82048
+4.35981 4.78063
+5.49932 6.08321
+1.0107 1.53369
+2.48759 2.94139
+4.24977 5.52034
+1.93104 3.35207
+-0.733247 1.22412
+-0.354283 2.36812
+6.34728 6.44213
+5.98172 7.8753
+5.47963 6.82986
+6.01986 6.6588
+4.62793 5.22134
+7.73923 8.29761
+8.85565 9.51494
+5.55307 6.15804
+6.30963 7.17248
+9.4775 10.2636
+7.45333 7.74006
+1.79317 2.33273
+7.73056 8.44999
+3.94172 5.02778
+8.36177 9.85172
+5.91765 8.12935
+7.95436 8.97583
+5.06238 5.37907
+4.56153 4.97175
+9.47572 9.65038
+9.54745 9.922
+7.82271 8.66299
+4.19056 4.75156
+4.15657 5.72352
+0.213845 0.312444
+2.30944 2.6806
+2.42391 3.41888
+6.00512 6.88274
+6.64546 7.61145
+-0.204229 2.78228
+-0.417104 0.667252
+8.18696 8.67785
+9.27818 9.67924
+-0.0174685 0.21355
+5.91137 6.39606
+9.49268 10.1457
+2.11362 4.36526
+6.51084 7.82167
+6.07066 6.44843
+-0.653518 1.08588
+7.46736 7.87137
+5.26045 7.92188
+6.4171 6.8133
+6.73709 7.70383
+3.46451 4.23679
+0.122365 0.809853
+7.98627 8.0505
+1.71192 2.63047
+1.20624 2.12087
+4.6812 5.51566
+2.62672 2.67648
+4.203 5.1052
+5.26482 6.5186
+3.68166 3.74701
+2.72011 3.98338
+3.41652 3.71477
+2.26211 2.90374
+0.930209 1.43211
+1.98603 3.36662
+4.55838 5.9933
+5.66292 6.59838
+3.12432 3.87457
+6.54384 8.38959
+0.205059 0.331022
+8.70617 9.34121
+7.02182 7.38679
+2.36908 2.84197
+9.13221 9.76563
+7.50113 9.49245
+8.15671 8.45093
+1.9517 2.20923
+3.23368 3.43695
+2.97273 4.10133
+7.36338 8.96733
+4.77525 5.18347
+9.47774 10.3537
+1.75218 1.97051
+5.42544 6.18939
+9.75801 10.0151
+6.31285 6.38327
+8.43389 8.721
+7.6108 7.81113
+8.72029 10.3153
+5.18655 7.1101
+7.96243 8.43151
+0.798103 0.860125
+1.1289 2.77549
+5.91084 6.03085
+4.95884 5.46913
+5.88125 6.49667
+7.9394 8.9545
+5.07492 5.55063
+5.92251 6.08548
+3.88602 5.41487
+1.40122 2.15276
+8.74244 8.83223
+4.75577 6.60338
+0.921272 1.44873
+3.77361 3.90348
+8.8999 9.8518
+3.11077 4.85674
+8.56185 10.6345
+8.76335 9.00169
+6.8734 8.60197
+4.54408 4.93892
+5.57849 6.31727
+7.95161 8.30843
+1.55798 2.4957
+3.86082 3.97131
+6.45433 7.17065
+0.96021 2.32897
+6.84576 6.89531
+8.59095 8.70199
+3.57754 4.26457
+5.27979 5.74385
+2.06602 2.90525
+3.0856 4.18179
+2.76214 3.9982
+2.11943 5.4285
+3.1197 3.24389
+0.495798 1.23632
+3.18253 3.99433
+7.02072 8.37949
+2.77905 3.42643
+1.57093 2.30655
+7.10979 7.14006
+6.20994 6.72092
+8.15136 8.33899
diff --git a/wasserstein/tests/data/test_200_B b/wasserstein/tests/data/test_200_B
new file mode 100644
index 0000000..761943d
--- /dev/null
+++ b/wasserstein/tests/data/test_200_B
@@ -0,0 +1,200 @@
+1.17434 1.46837
+2.58198 4.16589
+0.234041 0.968658
+1.52703 1.59579
+6.7103 7.44033
+3.19227 4.41539
+5.42556 5.57369
+3.45417 4.86089
+3.82256 4.1092
+7.82551 7.90784
+3.9384 4.71796
+5.60335 5.9054
+7.96663 9.8987
+6.30305 6.64853
+7.33246 10.5316
+0.623312 1.09008
+2.63041 2.64616
+5.36028 6.28956
+4.64202 5.91858
+7.55219 7.96304
+7.73736 9.18221
+1.67114 1.84851
+5.07514 5.12159
+7.03732 7.05228
+7.5006 7.59212
+0.244947 1.55875
+0.0170454 1.10485
+1.95394 3.53669
+5.66015 6.01949
+5.88211 7.64639
+7.46698 9.27085
+6.37429 7.10154
+4.54535 4.81932
+8.21203 9.35896
+4.89933 6.20802
+3.68683 4.17831
+0.477467 0.828394
+6.17871 6.77834
+9.77523 9.92676
+0.854808 2.38709
+7.93326 8.3553
+2.10917 2.27771
+4.07045 4.72793
+8.2016 8.8011
+2.9205 3.95746
+2.89806 4.39725
+5.5654 5.78669
+9.5219 9.98543
+7.08591 7.19588
+8.35359 9.57893
+9.81348 10.0345
+8.5994 9.71835
+5.43903 7.25234
+1.82768 2.92724
+4.44952 6.79754
+5.66747 7.34386
+5.88153 6.39253
+3.34008 4.22032
+2.46068 2.76051
+0.370778 2.61681
+6.02508 6.26809
+4.32654 4.93262
+7.41536 7.99616
+8.84229 9.87911
+3.8551 5.84353
+1.56832 2.34694
+6.96099 7.42028
+8.15753 8.72014
+9.23141 10.3815
+7.4484 7.80228
+0.473671 0.874895
+3.15689 3.50687
+3.58122 4.09945
+3.55022 3.74767
+4.42708 5.80211
+4.40956 4.68699
+3.80576 4.61856
+7.29965 8.28614
+7.40582 8.15308
+1.69789 1.77669
+1.66419 3.44308
+0.473997 0.872506
+7.83959 8.52898
+6.22416 6.36949
+-0.187159 0.871822
+0.232336 0.585965
+9.29905 9.44357
+1.4459 2.40589
+2.83008 3.19758
+1.15291 2.12112
+2.58686 3.33896
+6.79362 7.88068
+0.228178 1.48318
+5.60001 6.20258
+4.97803 7.10992
+1.70429 1.962
+2.72659 3.13886
+9.22714 9.25889
+3.84694 3.88778
+-0.282077 1.48155
+9.28756 9.58517
+4.34069 5.59751
+8.63909 8.76839
+8.86236 10.7642
+6.77597 8.41888
+7.30621 8.64164
+0.685607 1.22755
+2.91514 3.22638
+2.72098 3.66837
+8.17528 8.32638
+5.19632 5.7506
+7.34177 8.70639
+5.74082 6.35524
+5.95975 6.69284
+9.40187 10.4488
+2.92761 3.36735
+0.399531 3.13082
+4.83399 4.92635
+7.74539 8.56852
+1.76322 3.5086
+6.54479 6.72963
+7.64362 8.12404
+1.35542 1.45313
+0.214385 0.718085
+1.7006 3.21962
+5.91009 6.47862
+2.21093 2.34636
+5.96919 6.79365
+6.59951 8.22203
+1.54571 1.59397
+3.27012 3.79128
+0.32455 0.622995
+1.73926 2.78017
+9.81035 9.84077
+7.38441 7.85171
+8.90372 9.34186
+7.26323 8.41174
+5.7363 5.97348
+8.25473 10.1281
+2.3981 2.52096
+8.53783 9.63442
+8.51755 9.2735
+6.48614 6.773
+3.40182 3.65137
+2.1353 3.04852
+2.95397 3.73285
+6.98063 7.4963
+4.50189 5.26384
+0.21416 1.49363
+0.632196 1.36307
+6.57833 6.60481
+8.0634 9.33903
+2.79759 2.94462
+4.43747 4.58861
+6.48733 6.86569
+2.28008 3.47037
+6.87452 7.77431
+-0.156821 2.71557
+0.72595 1.78862
+1.97586 2.38196
+8.61839 9.1468
+4.55496 5.68986
+0.26923 1.15728
+9.63757 9.7236
+1.39497 1.96698
+4.8643 5.04172
+6.64675 7.66435
+2.56256 2.6015
+-0.381989 0.611211
+0.676336 1.26896
+8.95304 9.03243
+5.62058 6.07997
+3.36522 4.04276
+8.64868 10.5024
+4.75813 5.19834
+1.96608 2.05864
+9.01449 9.10397
+3.72786 4.51921
+5.6938 6.96584
+1.73499 2.9314
+2.73099 3.41409
+8.77171 9.07665
+4.63865 4.67649
+8.6698 9.30782
+-0.168259 2.09581
+9.29672 9.56
+0.372544 2.60567
+0.450487 1.32919
+6.95341 7.6399
+3.4403 5.24993
+5.53469 6.97831
+-0.79664 1.21306
+5.68831 6.14413
+8.85601 8.95444
+3.83309 5.211
+5.51573 6.5114
+3.64009 3.99648
+4.40759 4.99283
+1.85198 2.6457
+2.72645 3.74803
diff --git a/wasserstein/tests/data/test_5000_A b/wasserstein/tests/data/test_5000_A
new file mode 100644
index 0000000..094c6e0
--- /dev/null
+++ b/wasserstein/tests/data/test_5000_A
@@ -0,0 +1,5000 @@
+0.471299 1.89241
+2.82136 3.97846
+8.81923 9.20678
+1.42474 1.65425
+8.36963 9.16097
+-0.236476 0.692489
+7.57182 8.06148
+2.89878 3.21958
+7.1285 7.51707
+5.75496 7.09461
+6.00081 6.10914
+9.60869 9.64676
+7.42889 8.97174
+7.26061 8.55944
+2.41226 2.5146
+8.5616 9.44847
+7.4946 8.86962
+5.42244 6.98028
+9.62386 9.96039
+7.70591 9.92849
+1.34119 3.2048
+3.92169 5.15228
+8.82955 9.60318
+7.94213 9.39997
+2.6716 4.02057
+0.375206 0.497663
+1.94572 3.65599
+1.03366 1.46356
+8.91855 10.1838
+7.11087 8.64425
+2.63266 2.78706
+8.93611 10.2943
+8.51999 9.28356
+1.31436 3.13725
+1.92871 4.00178
+8.30503 8.45555
+2.58739 2.82076
+3.20419 5.29453
+7.4015 8.13225
+9.07991 9.74729
+0.822366 0.938371
+2.90508 4.29367
+4.32385 5.4787
+3.63054 4.6918
+8.52962 9.87004
+1.16994 2.39465
+2.61903 3.33772
+4.15505 4.52942
+8.7068 9.66579
+8.10373 9.31351
+0.7954 1.23001
+7.82253 8.69505
+4.59616 5.91996
+1.02032 1.93931
+6.98421 8.46017
+8.42263 11.3447
+2.63444 3.7158
+7.49059 9.1137
+-0.122109 1.41074
+8.29578 8.81161
+6.24793 6.32368
+4.07212 4.39695
+5.32453 7.457
+8.3892 9.82048
+4.35981 4.78063
+5.49932 6.08321
+1.0107 1.53369
+2.48759 2.94139
+4.24977 5.52034
+1.93104 3.35207
+-0.733247 1.22412
+-0.354283 2.36812
+6.34728 6.44213
+5.98172 7.8753
+5.47963 6.82986
+6.01986 6.6588
+4.62793 5.22134
+7.73923 8.29761
+8.85565 9.51494
+5.55307 6.15804
+6.30963 7.17248
+9.4775 10.2636
+7.45333 7.74006
+1.79317 2.33273
+7.73056 8.44999
+3.94172 5.02778
+8.36177 9.85172
+5.91765 8.12935
+7.95436 8.97583
+5.06238 5.37907
+4.56153 4.97175
+9.47572 9.65038
+9.54745 9.922
+7.82271 8.66299
+4.19056 4.75156
+4.15657 5.72352
+0.213845 0.312444
+2.30944 2.6806
+2.42391 3.41888
+6.00512 6.88274
+6.64546 7.61145
+-0.204229 2.78228
+-0.417104 0.667252
+8.18696 8.67785
+9.27818 9.67924
+-0.0174685 0.21355
+5.91137 6.39606
+9.49268 10.1457
+2.11362 4.36526
+6.51084 7.82167
+6.07066 6.44843
+-0.653518 1.08588
+7.46736 7.87137
+5.26045 7.92188
+6.4171 6.8133
+6.73709 7.70383
+3.46451 4.23679
+0.122365 0.809853
+7.98627 8.0505
+1.71192 2.63047
+1.20624 2.12087
+4.6812 5.51566
+2.62672 2.67648
+4.203 5.1052
+5.26482 6.5186
+3.68166 3.74701
+2.72011 3.98338
+3.41652 3.71477
+2.26211 2.90374
+0.930209 1.43211
+1.98603 3.36662
+4.55838 5.9933
+5.66292 6.59838
+3.12432 3.87457
+6.54384 8.38959
+0.205059 0.331022
+8.70617 9.34121
+7.02182 7.38679
+2.36908 2.84197
+9.13221 9.76563
+7.50113 9.49245
+8.15671 8.45093
+1.9517 2.20923
+3.23368 3.43695
+2.97273 4.10133
+7.36338 8.96733
+4.77525 5.18347
+9.47774 10.3537
+1.75218 1.97051
+5.42544 6.18939
+9.75801 10.0151
+6.31285 6.38327
+8.43389 8.721
+7.6108 7.81113
+8.72029 10.3153
+5.18655 7.1101
+7.96243 8.43151
+0.798103 0.860125
+1.1289 2.77549
+5.91084 6.03085
+4.95884 5.46913
+5.88125 6.49667
+7.9394 8.9545
+5.07492 5.55063
+5.92251 6.08548
+3.88602 5.41487
+1.40122 2.15276
+8.74244 8.83223
+4.75577 6.60338
+0.921272 1.44873
+3.77361 3.90348
+8.8999 9.8518
+3.11077 4.85674
+8.56185 10.6345
+8.76335 9.00169
+6.8734 8.60197
+4.54408 4.93892
+5.57849 6.31727
+7.95161 8.30843
+1.55798 2.4957
+3.86082 3.97131
+6.45433 7.17065
+0.96021 2.32897
+6.84576 6.89531
+8.59095 8.70199
+3.57754 4.26457
+5.27979 5.74385
+2.06602 2.90525
+3.0856 4.18179
+2.76214 3.9982
+2.11943 5.4285
+3.1197 3.24389
+0.495798 1.23632
+3.18253 3.99433
+7.02072 8.37949
+2.77905 3.42643
+1.57093 2.30655
+7.10979 7.14006
+6.20994 6.72092
+8.15136 8.33899
+0.903753 1.57921
+0.380744 1.88053
+1.3164 1.79885
+0.199366 0.576639
+5.53683 6.49433
+8.8705 9.14396
+3.1401 3.98761
+4.82675 6.69396
+7.28593 8.08916
+8.11312 9.92914
+3.25737 3.42109
+2.58413 4.57223
+2.65202 2.77196
+-0.31616 1.51568
+4.1621 5.29563
+4.49155 5.21037
+7.28481 7.31722
+9.70568 10.0406
+2.39057 2.85874
+2.30626 3.16244
+1.15896 2.09616
+5.91343 7.33024
+-0.172181 0.177363
+5.08934 6.10928
+7.15508 7.55315
+4.43036 4.68093
+6.00772 6.49566
+7.9247 8.43809
+1.57028 2.52328
+3.45458 4.43692
+3.18257 4.83824
+1.48243 1.91225
+2.59025 2.99596
+6.93059 8.34359
+4.53752 7.51216
+6.42857 6.51513
+5.5663 6.13877
+7.54367 7.56485
+9.01229 9.19913
+2.84158 3.23347
+0.42959 0.620618
+8.77033 9.33787
+8.06103 8.30989
+6.48425 7.83668
+4.66949 6.00205
+4.46683 4.66247
+8.96738 9.07714
+0.463093 0.514808
+7.72986 9.44537
+6.31391 6.8289
+0.883295 1.70946
+3.73278 3.98015
+6.73453 6.92514
+3.58434 4.43262
+0.236286 1.4601
+2.00505 2.38684
+3.845 4.20708
+1.18852 3.04911
+0.766784 1.00641
+7.38781 8.11216
+8.9396 9.27589
+0.369822 1.53322
+8.76527 9.23987
+0.663408 0.803445
+9.69209 10.1455
+9.73379 10.234
+3.47602 4.89968
+4.12754 5.45249
+7.31984 8.57369
+0.989101 1.47678
+5.57662 5.83292
+4.99092 6.85044
+4.35272 4.3683
+0.0517815 1.92227
+7.2694 7.80634
+1.35565 1.42783
+8.5638 8.91707
+1.74557 2.74123
+2.18226 2.19664
+-0.901334 1.32691
+0.866613 1.03788
+5.30895 6.31774
+7.70178 8.5675
+4.06894 4.16071
+2.59697 3.53162
+4.30201 5.34212
+4.08762 4.19091
+-0.516192 0.848397
+9.85911 10.1066
+0.472991 1.40069
+6.26012 7.0054
+0.707801 2.15445
+1.73825 1.87193
+0.206301 0.831746
+7.77872 7.92715
+4.94477 5.60361
+3.86216 5.16839
+1.35166 1.54482
+2.91721 3.56193
+4.57242 4.75913
+7.09303 8.29678
+8.18431 8.92151
+6.80303 10.87
+1.29208 1.72027
+1.22224 1.31693
+5.26756 6.26459
+2.55221 3.94397
+6.58902 6.78354
+7.85917 8.89791
+6.59279 7.63115
+4.45787 7.26828
+3.48759 5.33991
+2.13838 3.86589
+1.53368 3.57313
+1.41722 3.19336
+3.48388 4.11958
+1.53756 2.98451
+7.29083 8.22109
+1.2713 2.16915
+6.94685 7.31029
+6.2494 7.04676
+3.00376 3.02028
+1.25232 1.43301
+1.50413 2.25
+2.89098 4.77198
+4.50766 5.89294
+5.5403 6.07893
+-0.101858 0.409209
+3.87963 6.1053
+-0.19564 1.46589
+-0.342077 0.694623
+6.63875 7.42223
+7.89982 9.05857
+4.91121 5.48031
+5.90743 8.35815
+7.13881 8.21597
+4.11493 5.08147
+3.59673 3.77176
+8.08236 8.3237
+1.35842 1.48934
+5.42963 5.85906
+4.60778 4.9734
+-0.607198 0.91225
+5.40263 5.7017
+5.08624 5.63236
+7.34529 9.02233
+7.30013 8.12907
+6.56106 6.75585
+6.82576 7.25434
+2.96037 3.56454
+3.60283 4.09137
+6.35408 6.71888
+-0.688103 0.84579
+8.45128 8.69771
+6.31749 7.3294
+5.82223 6.04761
+1.72983 2.38205
+6.94974 7.76985
+9.681 10.0141
+8.65394 9.2456
+2.52904 3.39548
+6.66609 7.35785
+4.18963 4.5473
+3.58643 3.80513
+2.88796 3.82413
+0.992066 1.1477
+4.57942 5.15419
+3.02826 4.32268
+5.91565 6.82087
+4.13694 5.13393
+6.28717 6.53257
+1.3149 2.36944
+0.488974 0.981461
+4.32763 4.98272
+-0.420836 0.63619
+7.13406 7.31362
+0.367782 1.91138
+6.14763 6.16713
+0.837933 1.92794
+9.3781 10.0609
+3.22887 5.44584
+5.91554 6.65974
+5.68608 6.02435
+7.99715 8.55953
+5.37106 5.38574
+0.254544 0.374268
+0.184701 0.917061
+9.38005 9.54042
+6.86741 7.35628
+0.87398 1.69093
+7.75845 8.53773
+0.370425 1.35335
+0.699837 0.810893
+3.73223 4.32089
+3.81804 3.85752
+4.85936 5.10097
+2.70381 3.10519
+3.82523 5.27699
+9.13422 10.3317
+4.62775 4.77988
+7.91139 7.95504
+2.72614 4.79958
+0.863357 1.88643
+4.14155 5.02327
+2.49683 4.11585
+1.06741 1.11516
+6.20979 8.38443
+0.936362 2.46703
+6.58231 7.85063
+1.89469 2.31422
+8.70668 9.14006
+5.76486 6.1122
+3.15778 3.76679
+0.248282 2.19881
+1.25317 1.92694
+7.81837 9.53067
+-0.582906 0.818904
+8.34194 8.37845
+4.4913 5.10164
+3.86376 5.5453
+6.94054 7.68699
+2.07462 2.5811
+0.518698 2.1529
+3.51773 4.60946
+8.39915 8.98446
+1.63685 2.19755
+6.60737 9.05917
+2.06667 3.23994
+3.18822 3.31219
+2.44332 3.22088
+4.755 4.87118
+4.34245 4.91565
+4.64562 4.8104
+2.73282 3.35646
+9.48057 9.86441
+0.640899 1.03356
+0.789475 0.925731
+1.4247 1.58347
+1.47747 2.25408
+8.8612 9.81597
+8.44147 10.6885
+9.07046 10.0877
+0.350125 1.15765
+4.45375 5.73964
+4.06526 4.26457
+7.50776 8.23491
+1.55452 1.63786
+2.8399 4.52559
+1.34319 1.47951
+5.21572 5.65702
+5.85695 6.75574
+8.21826 10.657
+-0.0479956 1.79162
+1.72905 1.78113
+3.35685 4.03797
+3.7123 5.82296
+8.56751 10.2992
+4.07987 4.25273
+5.8347 6.07253
+3.25283 3.99065
+9.31995 10.3647
+0.649025 1.14496
+1.06966 2.04182
+7.59831 7.85826
+3.35263 3.84374
+4.91371 5.10148
+8.0875 9.23421
+3.00484 5.14282
+8.60448 9.09442
+5.61429 6.24037
+3.4729 4.17907
+7.18702 7.26274
+0.729966 0.928899
+2.27264 2.81241
+2.67248 3.91661
+3.98443 4.64406
+5.50463 6.92435
+-0.257961 0.905736
+5.71363 6.67387
+4.12643 4.66467
+3.97623 4.64917
+9.71227 9.8243
+8.66674 8.97634
+7.94673 8.73904
+7.45228 8.14466
+3.78405 4.81189
+4.05505 5.00011
+2.84957 3.15451
+6.93785 7.58172
+1.85006 1.96814
+6.82256 7.00166
+2.42727 2.68161
+8.06129 8.76308
+1.53758 3.67482
+2.5057 4.18495
+7.09618 7.79664
+1.12843 1.46228
+1.61447 2.2668
+5.58639 5.70776
+8.15398 8.34959
+2.49733 2.57643
+5.18817 5.32462
+5.62963 5.86377
+1.95215 2.26641
+7.22129 7.23255
+5.99833 6.18639
+6.20875 7.13868
+6.814 7.6597
+7.41314 9.49798
+5.48819 6.31634
+4.81318 5.08156
+9.15434 9.42787
+4.83201 5.43295
+1.44477 2.6455
+8.8907 10.4727
+3.19487 3.21255
+1.47291 3.13113
+4.14796 5.10058
+5.85016 8.41212
+7.58183 8.53659
+9.5978 10.2877
+1.5954 2.58394
+2.65561 4.0975
+-0.157024 0.16627
+7.04379 7.75368
+2.39896 2.7728
+2.42376 3.58085
+0.158653 0.857045
+7.82101 9.01833
+6.80499 7.35261
+6.62833 6.66255
+4.90229 5.45681
+8.50205 8.69236
+2.01845 2.06924
+8.2503 9.04222
+4.58265 5.52758
+8.6176 9.74887
+1.28468 1.77019
+5.40424 6.20705
+0.943905 1.98023
+4.2702 4.41287
+3.89454 4.4814
+0.585132 1.56351
+9.45354 10.5374
+3.7501 5.07553
+7.53248 8.14004
+4.60026 4.78921
+1.61073 4.22368
+6.22591 7.40966
+0.57866 1.0522
+5.877 6.55882
+3.54573 3.7731
+7.64294 7.66103
+8.2399 9.14032
+0.307808 0.571367
+7.89791 9.25734
+5.2852 5.84332
+0.45713 2.42223
+7.73426 8.48158
+8.0058 9.46405
+8.03189 8.41868
+1.54624 1.98914
+7.24167 7.27699
+8.61226 8.83199
+5.38365 6.52599
+0.827018 1.51428
+7.19285 7.48372
+-0.0969552 2.16007
+4.08084 6.32563
+9.16026 10.2604
+0.206147 0.717435
+4.00643 4.8093
+2.16139 3.14759
+1.73359 3.13485
+9.1103 9.36052
+7.05621 7.43901
+4.83509 6.07581
+5.67164 7.89488
+7.93353 8.18454
+2.59566 3.1842
+3.62521 4.95121
+3.0297 3.18649
+1.08515 2.69289
+3.77063 5.7789
+0.106035 1.27409
+0.601099 2.13481
+6.98837 7.58833
+9.22955 9.79149
+1.6398 1.78726
+2.30423 3.34814
+2.3912 2.81842
+4.71724 6.16966
+5.13553 5.5016
+5.34117 5.45075
+9.32776 10.0676
+4.54244 5.29058
+4.01337 5.73188
+8.17427 8.39652
+1.96122 2.6921
+0.594267 1.00176
+-0.136973 0.977133
+6.41362 6.78056
+1.68388 2.39891
+9.50795 10.2315
+-0.262703 1.15557
+8.72229 9.683
+5.41821 5.67519
+4.93514 7.15867
+4.07046 4.26702
+-0.00866106 0.252353
+8.65877 10.1527
+2.10958 3.40353
+2.94947 3.43201
+6.32014 7.06279
+2.55034 2.89646
+3.87777 5.68044
+2.05325 3.00968
+5.11855 6.55784
+8.99618 9.22608
+3.36303 3.84902
+2.6234 3.70832
+7.35189 8.30856
+6.43777 7.28495
+5.33954 5.48055
+0.15999 0.391114
+3.4492 5.07088
+2.38503 2.42742
+3.88912 4.93246
+2.76303 4.54991
+6.56261 7.60381
+3.64198 3.72471
+1.70542 1.78806
+9.71115 9.88315
+0.471586 1.82377
+9.27611 10.5725
+0.486889 0.851587
+4.39234 5.10637
+9.54209 9.8955
+6.99602 7.42461
+2.98797 3.74623
+5.89424 6.4498
+9.63845 9.86333
+4.39828 5.18646
+2.30118 3.5758
+8.68128 9.56011
+9.00505 10.4304
+-0.22184 0.233296
+6.48492 7.60283
+1.54156 2.60693
+4.06808 6.39369
+5.52361 6.26241
+-0.698727 0.745524
+2.30742 2.41924
+0.655833 1.65752
+6.94733 7.81866
+7.83136 9.10651
+6.45284 7.1931
+6.09683 6.66159
+9.03299 9.4163
+1.86392 3.26189
+0.54863 2.07194
+0.364026 1.38376
+0.706954 1.0736
+-0.111015 0.584367
+1.54265 2.1413
+0.501172 0.57928
+2.09411 2.28902
+1.89894 4.09104
+8.72895 8.87045
+5.27709 5.72545
+0.164581 1.64188
+8.39203 8.73608
+8.21523 8.45002
+9.62006 10.1665
+4.79076 6.26442
+3.44189 3.68669
+8.93789 9.38343
+7.07036 7.64194
+8.34396 9.56445
+8.29992 8.64954
+5.82566 7.83287
+2.43008 3.4476
+1.81121 2.12203
+4.36108 4.3842
+6.28756 6.95939
+3.8698 5.79519
+0.644581 0.699162
+9.71982 10.2422
+4.86545 5.00544
+8.3808 9.29356
+1.34495 1.40972
+1.03641 2.01838
+8.55609 9.99958
+1.40813 3.46097
+3.20928 4.08838
+8.24345 9.11587
+1.27604 2.03462
+8.28298 8.46252
+2.20644 3.19585
+1.91396 2.30108
+4.2553 5.66006
+7.34925 8.38275
+6.28319 7.22199
+8.42171 9.62596
+1.12059 1.18262
+1.37555 1.84196
+4.39663 4.93639
+9.28044 9.58437
+5.47407 6.88593
+8.36529 8.49813
+9.40208 10.5922
+-0.451389 1.92404
+2.89431 3.19453
+6.51433 8.02158
+5.52163 6.06786
+7.63525 9.86457
+4.13898 5.05845
+0.136662 0.503748
+6.13492 6.74997
+8.37416 9.18971
+8.64164 8.82663
+0.941173 1.16158
+6.9073 8.26916
+8.37278 8.44326
+8.8951 9.20427
+8.40149 9.17577
+3.60361 4.57183
+8.67263 10.1127
+5.89716 6.45412
+1.97285 2.35593
+7.22973 8.13467
+9.55645 9.92529
+0.261578 0.836274
+9.04414 9.45485
+6.18043 6.54229
+8.88579 9.54087
+1.82613 2.93849
+5.7599 5.96366
+5.23105 5.5541
+0.425229 1.44436
+0.32065 2.60892
+7.83655 9.48786
+2.3168 3.45972
+2.35466 3.23342
+8.24494 8.27258
+7.32678 7.74264
+8.37275 10.0741
+4.17337 4.98348
+-0.162009 0.724431
+9.49757 9.76377
+8.69435 9.08089
+4.13841 4.7514
+7.26358 7.55514
+6.91912 6.93
+6.7883 7.18296
+-0.614315 1.1857
+6.05907 7.33557
+4.86704 4.87705
+8.50012 9.14836
+1.83683 3.09895
+6.16389 8.39248
+3.03556 4.41004
+4.72416 5.05782
+1.98183 3.19183
+2.77103 5.71501
+4.90002 4.9817
+0.269258 0.725628
+5.59551 7.05038
+2.95416 3.09633
+2.17662 3.18385
+6.67536 7.56762
+7.31678 7.39321
+3.84158 3.85359
+4.38203 5.10149
+0.816784 1.09918
+0.70131 0.739502
+0.276631 2.32633
+9.15839 9.49433
+0.721295 1.97673
+2.63875 2.75437
+5.00344 5.5645
+2.24555 2.81234
+7.74465 9.07646
+2.35244 4.90632
+0.812093 0.954419
+3.97904 5.2071
+4.19177 4.83646
+0.853012 1.331
+2.64112 3.25613
+0.0894716 1.61954
+3.39617 3.40859
+1.56906 2.28518
+2.37258 4.36515
+1.60997 1.7561
+5.15275 5.33281
+6.47824 7.47529
+2.51145 3.29949
+2.71094 2.77785
+8.84653 9.48398
+1.3246 1.66664
+7.43718 7.5546
+3.68985 4.24649
+4.50553 4.51669
+4.15617 4.54887
+8.55319 10.2136
+2.1448 3.55805
+4.64594 4.71505
+1.71763 1.99977
+4.98066 5.46709
+7.7779 8.36497
+-0.0604997 0.301294
+5.11873 7.32867
+4.94567 5.5986
+5.32645 6.26835
+2.5768 3.13511
+3.31604 3.87555
+1.60834 2.68762
+3.30552 3.85211
+4.26741 4.98636
+0.820475 1.18854
+7.91501 10.7203
+5.17391 5.30351
+4.00452 5.75141
+2.37722 3.4602
+2.2373 2.94837
+1.62462 3.48264
+7.98507 9.2566
+5.32504 5.56388
+0.760614 0.7802
+0.855659 1.01522
+3.11231 4.43223
+5.62821 6.21564
+4.96845 5.35921
+8.10559 9.11106
+1.02533 1.13103
+6.99976 7.0788
+1.87628 2.58801
+1.11023 2.24655
+5.23343 5.45086
+0.95875 2.25343
+7.45917 8.23614
+2.72245 3.04663
+8.66816 8.70698
+5.55734 7.12262
+1.01935 1.88271
+0.804417 1.76187
+7.82703 8.78426
+4.77321 6.15199
+2.91503 3.69352
+0.776735 1.08883
+5.19981 5.46442
+9.06483 10.4008
+7.72082 8.26398
+2.9854 3.26573
+0.584028 2.60443
+0.700994 1.10379
+5.47612 5.94502
+-0.318442 0.986786
+5.0704 5.08055
+3.83732 4.4826
+5.60843 6.59005
+8.81432 9.7851
+6.28792 6.65284
+1.16812 2.27701
+7.15234 9.66795
+9.02188 9.15339
+1.76112 2.04839
+7.49419 7.6204
+5.1765 5.497
+1.45855 1.94969
+1.35003 1.55822
+2.50453 2.86815
+7.10451 8.51352
+3.87727 4.1124
+1.84876 2.79351
+3.01661 4.05396
+-0.16814 0.366484
+-0.538895 0.608786
+7.59933 9.00744
+0.938648 2.38471
+5.76934 6.16572
+8.20416 8.62505
+8.64542 8.7264
+2.75784 2.7828
+0.794451 1.97817
+9.21331 10.5156
+8.46671 8.80572
+3.94814 5.16845
+6.73654 6.97397
+4.05301 4.93008
+6.37833 6.77985
+7.21161 8.15994
+3.74993 4.61029
+-0.127938 1.09853
+2.82957 4.28816
+6.50564 6.59445
+8.37926 8.48332
+0.757443 1.74585
+0.232438 0.972293
+6.99187 8.7098
+7.20368 8.44301
+4.4801 6.07501
+4.34015 6.1495
+2.19394 3.22334
+7.29817 8.41021
+1.16627 2.68901
+4.62423 5.08039
+0.955655 2.22882
+1.45862 3.07065
+1.69815 2.56291
+4.01179 4.36587
+7.135 7.75829
+6.6823 7.27765
+5.44745 5.67195
+4.94594 5.42067
+0.267772 0.301939
+0.676432 1.6296
+1.37335 1.91645
+1.89051 2.38631
+4.84386 6.30539
+8.95613 10.944
+2.18119 2.41821
+5.74901 6.16952
+7.5431 7.88071
+9.05278 9.8128
+0.201334 1.65323
+2.82787 3.82083
+3.07073 3.08475
+8.99671 10.1766
+5.43261 6.12137
+4.83693 4.86848
+6.31804 7.21544
+2.34491 3.2562
+6.05941 6.53725
+-0.483381 1.17347
+5.53777 5.72651
+3.28875 3.47472
+3.94609 4.9418
+7.45585 8.6871
+1.50066 2.57215
+8.10112 8.67954
+6.24737 6.42635
+0.64413 1.05759
+7.1741 8.21476
+0.502722 1.77462
+0.783663 1.74174
+9.52704 9.9109
+-0.473873 2.01013
+7.07946 7.11474
+0.857335 1.6501
+4.00225 4.84453
+5.40598 6.30573
+8.18802 8.30067
+9.00412 10.9588
+9.8362 10.1517
+7.62735 8.37572
+3.41477 4.63099
+2.51254 2.81559
+6.36702 6.56061
+5.11842 5.35515
+5.21873 5.73296
+5.73528 7.77276
+3.64993 4.66826
+7.12664 8.46553
+8.7257 9.16851
+1.27615 2.20376
+7.46188 8.20752
+2.64939 2.66373
+4.94147 6.0509
+6.3805 7.48841
+6.25197 7.12327
+0.0885331 1.2682
+4.97356 6.58488
+4.11917 4.27267
+9.08793 9.70385
+0.897277 1.31702
+6.87538 8.25544
+1.55565 1.59492
+2.62483 3.54274
+1.49631 2.92263
+9.45305 9.97728
+6.24087 6.4577
+3.94636 5.13669
+-0.000956745 1.08235
+1.46134 1.83767
+9.18517 10.6601
+-0.740186 1.81269
+5.81977 6.15818
+7.0529 7.99421
+6.17753 7.49749
+8.63091 9.04205
+9.65219 10.1558
+3.12839 4.99211
+2.97262 4.07384
+4.28605 4.33171
+4.15906 5.6805
+1.35165 1.50732
+0.524207 2.12307
+5.32468 7.01472
+3.16982 4.87893
+6.88786 8.34191
+3.81703 5.22335
+3.86772 4.37359
+8.19386 10.0705
+1.73155 3.16695
+4.31685 4.62261
+9.40618 9.89612
+4.41215 5.19659
+2.35595 2.63543
+7.88481 8.14203
+7.17062 10.3534
+9.41379 10.389
+7.99867 9.01239
+3.31382 4.04915
+5.39222 6.07657
+8.5187 8.65976
+9.30132 10.6131
+7.17351 7.93596
+4.80134 6.72724
+3.59756 4.65182
+1.08248 1.17479
+1.03124 1.06871
+6.43154 6.95098
+-0.102199 0.59801
+4.94795 5.18081
+6.39126 7.30258
+1.52738 2.04271
+1.80373 2.33093
+2.72251 3.01677
+0.296722 1.10844
+6.39104 6.51567
+8.70965 8.78714
+2.07858 4.41695
+1.91027 2.9718
+1.42944 2.01864
+1.96347 2.73397
+4.0701 4.22456
+4.02859 4.05107
+7.10977 7.98092
+8.21148 9.54287
+6.59231 7.65109
+0.144191 0.830665
+2.0192 2.23704
+8.03482 8.39591
+8.90473 9.98543
+2.18284 2.70166
+3.05569 3.54238
+8.35319 9.39539
+2.00803 2.42866
+2.35282 3.13763
+2.20155 2.79377
+1.76531 2.94892
+7.52749 7.72567
+3.02266 3.24778
+4.01741 4.22521
+9.75263 9.91571
+6.45502 6.67838
+2.24912 3.47262
+1.84372 2.26517
+4.09559 5.71188
+1.43811 2.33732
+3.89171 4.16905
+3.01506 3.9725
+0.0273168 1.51766
+5.04118 5.80507
+3.08517 4.17316
+8.81637 8.8332
+8.74055 9.50143
+2.36904 2.69008
+6.39733 6.44221
+8.53272 9.51114
+9.48423 9.55002
+8.65645 9.04872
+6.66352 7.48009
+5.64389 7.88656
+5.75301 6.6759
+3.28645 4.22757
+4.99482 5.82988
+3.00004 4.0273
+1.45249 1.56662
+4.96263 5.32195
+7.91351 8.1437
+1.02034 1.56249
+0.71376 1.73319
+0.709968 1.44651
+9.01414 9.54799
+4.02116 4.68005
+7.10903 7.27075
+7.21322 8.71031
+1.6644 2.27186
+3.71304 4.68764
+9.66257 10.1452
+5.34477 5.46136
+9.27722 10.583
+3.82328 4.83316
+4.77019 5.07928
+9.07112 9.23836
+6.99091 7.25634
+2.11871 2.3054
+7.88242 7.98572
+0.570809 0.714073
+8.51532 9.49151
+0.329247 2.48897
+4.78202 5.36476
+1.47969 2.78867
+6.75011 7.36769
+2.31162 2.39533
+3.50434 4.48026
+5.84603 6.28861
+7.5337 7.62538
+1.09955 2.85741
+6.09915 7.20381
+0.933825 2.37925
+0.576363 2.0182
+3.12126 3.22507
+2.85313 3.02656
+3.25724 3.92077
+5.48575 6.58011
+1.02824 1.65415
+8.68703 9.06219
+3.28389 3.86349
+5.80264 6.12775
+7.11846 7.47444
+1.29638 3.38601
+6.37908 7.05986
+-0.592438 0.854361
+0.39233 1.17768
+2.1497 3.94423
+2.42336 2.43441
+6.94806 8.30626
+0.79865 1.4173
+1.41455 1.43684
+0.240074 1.16712
+4.18593 5.9929
+6.161 6.564
+0.726091 1.90706
+0.375606 0.694866
+4.09349 4.26452
+2.01652 2.68038
+8.99301 9.90549
+8.93909 9.17673
+1.10427 2.01247
+9.12668 9.15282
+1.08098 1.55374
+0.377836 0.414809
+7.28611 8.86318
+8.3542 8.53251
+3.86353 4.12875
+6.7631 7.40068
+4.61679 4.78182
+2.12935 3.45492
+3.68233 4.0457
+6.68131 8.22111
+8.79197 8.80474
+1.8915 2.26287
+0.387586 3.073
+6.46798 7.57381
+7.79742 9.34526
+-1.21538 1.67303
+2.07845 2.66028
+3.14148 4.46647
+1.66789 2.73375
+8.49821 10.0574
+8.42537 8.89906
+0.618349 2.72887
+6.8229 7.54501
+6.99343 7.35322
+7.34223 8.68781
+3.18834 3.98274
+8.86908 10.2535
+3.39839 3.76171
+0.188168 0.392276
+1.68187 3.53401
+6.50423 6.71714
+7.61191 8.89715
+1.68463 2.09275
+5.94627 7.6003
+2.15865 3.24126
+7.93639 8.53826
+2.99626 3.43273
+7.71028 8.41172
+3.19472 4.60878
+8.36123 8.92549
+8.92975 9.02783
+2.87187 3.49672
+6.76949 7.71139
+8.09121 9.31151
+6.84199 7.44009
+0.730655 0.800873
+7.5208 7.54109
+6.75992 7.55017
+6.09818 6.17399
+0.639209 1.27283
+3.01917 3.22327
+1.69181 2.60614
+9.49245 9.5842
+-0.418034 1.08035
+5.77705 6.4705
+6.79362 8.51993
+9.73155 9.81609
+3.71503 3.92022
+6.18589 6.77634
+3.94124 4.23942
+7.59911 8.05275
+3.68865 5.10948
+7.63926 8.63019
+-0.049855 0.0844425
+-0.41188 0.807786
+1.35962 1.81039
+5.40579 6.15098
+1.38594 2.0059
+6.93444 8.71958
+7.01229 9.38008
+-0.0974976 0.962679
+4.74131 6.59152
+1.02343 1.59245
+1.55629 1.9128
+6.28353 8.38021
+5.66349 5.79644
+1.72629 2.28563
+1.64539 2.82654
+0.359466 1.05106
+4.37569 4.82703
+5.87657 6.37853
+1.46316 1.65333
+7.44494 7.5985
+1.16846 1.98579
+4.43371 4.93234
+2.31838 2.47777
+7.52687 8.44423
+6.08056 7.42253
+9.16144 9.94783
+4.74382 4.95616
+0.248344 1.05335
+6.12345 7.43941
+9.45647 9.99799
+3.77124 4.75199
+3.31315 3.44873
+-0.0909828 1.51271
+7.03234 8.02546
+8.11403 9.11461
+6.734 7.34799
+1.08903 1.18319
+2.72871 4.31607
+6.53688 7.52754
+1.07868 1.27792
+6.28409 6.56795
+4.89866 5.79458
+9.06994 9.1221
+2.54989 3.14338
+3.69971 5.71717
+3.7113 4.55076
+8.91864 9.64522
+8.75634 8.82359
+9.02242 9.03869
+3.59945 4.20169
+4.98557 5.07401
+4.81526 5.74009
+7.264 8.63749
+2.79579 4.43389
+2.87204 4.66432
+2.32487 3.72127
+3.99704 4.72567
+8.17229 9.0158
+-0.72926 0.823658
+2.52355 3.32725
+5.3446 6.63868
+4.48935 7.37833
+3.08173 3.0968
+2.41585 3.23026
+9.23187 10.5413
+5.50099 5.51888
+1.29634 1.88846
+-0.0113225 1.41526
+6.34508 7.53417
+0.383019 2.25144
+5.0649 5.40222
+3.08221 3.76296
+9.29111 10.6833
+2.19714 2.94735
+8.75711 9.48583
+8.61564 8.69349
+1.9362 3.96191
+3.7962 4.44382
+7.78501 9.03843
+5.79649 7.29675
+6.03048 7.4316
+1.31105 4.36446
+6.5882 7.03622
+4.88148 7.12474
+6.62305 6.90973
+2.27488 2.73731
+8.42703 9.28888
+7.72928 8.53989
+7.27021 8.63879
+0.992908 1.92001
+-0.282737 0.511292
+7.88963 8.03117
+6.93371 8.26148
+-0.0346633 0.403617
+8.7827 8.82558
+5.16876 5.59742
+8.61275 8.73843
+5.70578 6.02783
+9.08706 9.35903
+9.32728 9.83021
+9.20058 10.2497
+6.79824 7.3024
+7.17979 7.51783
+0.918555 2.67878
+7.9662 8.63241
+8.85903 10.3145
+9.34614 10.1964
+9.05027 9.79872
+8.28959 8.45837
+1.32518 2.04557
+8.72848 9.16742
+5.92126 6.77277
+8.31504 8.78631
+1.02487 1.70172
+4.45204 4.72842
+8.20636 10.4724
+5.86211 6.25457
+6.15754 7.71303
+8.37832 8.82577
+4.25233 4.59417
+9.41451 9.95324
+9.372 10.4461
+1.8346 2.7144
+8.00681 8.14717
+7.03997 7.06753
+7.16892 7.70102
+7.01781 7.46799
+1.78526 1.7969
+1.63304 2.2011
+8.59718 8.61083
+9.43498 10.3636
+4.98718 5.32487
+3.65451 4.89601
+8.82368 9.11333
+-0.104862 0.598773
+4.97756 5.62342
+1.99876 3.24686
+2.32242 4.01096
+4.04914 4.77892
+3.81545 4.32583
+3.30153 3.46783
+3.14287 4.04718
+8.65711 8.76768
+9.09385 10.6898
+4.82771 5.64405
+5.98783 6.36785
+7.93397 9.6543
+4.89726 5.65486
+5.08717 5.22314
+6.59377 7.23748
+3.58289 3.98597
+0.177884 0.397629
+5.30856 5.79257
+2.53943 3.98007
+6.51217 6.59644
+0.196888 1.99904
+3.8709 4.1901
+2.37646 2.50997
+7.03837 8.13287
+6.8674 6.89535
+0.576964 2.08851
+0.902928 2.86981
+8.59261 9.20279
+5.96621 7.49899
+0.617602 1.83267
+2.29189 2.6361
+4.34207 4.61026
+6.19963 6.76443
+1.15955 1.44068
+5.25852 6.33905
+6.37306 7.53103
+9.13334 10.039
+8.67743 9.93959
+5.62973 6.04375
+8.32286 8.77042
+3.28772 6.1722
+4.97902 5.47249
+3.37765 5.07238
+4.58025 4.84341
+2.76807 3.18817
+4.27581 4.43023
+6.92572 7.68461
+0.279247 1.0561
+1.10903 2.61106
+6.71708 6.73132
+2.66415 3.75702
+8.0513 9.80334
+4.82466 6.04232
+2.59971 2.85768
+9.04689 9.73945
+3.48338 5.16622
+7.90925 8.92774
+7.30264 8.06247
+7.59087 8.26476
+0.150315 0.423068
+8.62726 9.74636
+9.01983 9.71707
+6.84007 7.40541
+8.87829 9.48342
+2.69214 3.71481
+0.580036 0.77289
+9.474 9.83397
+5.80151 6.08527
+3.63837 5.27137
+8.5848 8.65779
+7.88338 8.13276
+3.27992 4.20963
+6.21244 7.28079
+-0.348924 1.38478
+5.26688 5.93787
+3.78941 5.01009
+6.41929 8.38529
+1.41724 1.67733
+0.212821 1.58246
+0.0697189 0.160497
+9.57839 10.2377
+9.03332 9.70645
+4.94572 5.15163
+3.16999 4.536
+5.77494 6.68359
+5.89258 6.11852
+7.72257 8.21668
+8.42501 8.44905
+8.7196 8.86465
+4.392 5.1076
+1.88249 2.54422
+1.38092 1.60326
+5.04142 6.37374
+4.31795 5.91152
+1.79399 2.09314
+6.65405 8.32262
+1.36356 1.58538
+5.45456 6.55824
+4.95807 6.22848
+8.72077 10.2825
+0.745968 2.01546
+6.85041 7.11076
+4.82028 5.34442
+5.77673 8.01294
+8.58582 9.33714
+8.49884 9.21533
+9.05574 9.4096
+3.19932 3.27024
+9.50227 9.96685
+0.771636 1.0617
+9.00621 9.36397
+-0.097167 1.39463
+7.79622 8.43537
+8.05228 10.1504
+2.21685 4.17072
+1.82476 2.45381
+4.34408 4.56578
+9.27538 9.54701
+6.80153 7.44115
+7.38884 7.84448
+7.17526 8.00165
+5.85812 7.67326
+5.25545 6.30791
+5.68518 5.94055
+3.77685 4.1545
+0.530928 0.737248
+3.9772 4.59563
+8.96322 9.45618
+7.98322 8.44165
+3.42929 4.22329
+3.66445 4.7583
+-0.183652 0.434842
+3.16492 3.95726
+6.87407 7.89944
+5.08921 5.7745
+2.85466 3.04505
+7.12685 7.41248
+0.715419 0.876676
+3.47441 5.21753
+9.13594 9.87799
+5.52459 6.35691
+5.12544 6.12935
+2.44296 2.91543
+2.75148 4.19886
+1.43478 4.3919
+6.6352 7.07768
+4.72283 5.11506
+6.36434 7.69268
+2.32643 2.75289
+5.46566 6.22854
+6.37995 6.76989
+1.52564 3.55871
+1.05807 2.19393
+1.95374 4.08727
+8.11273 8.12767
+2.85955 4.71355
+4.89009 6.88516
+2.06859 2.25512
+7.50556 8.77923
+4.43353 5.11915
+5.16308 5.9695
+1.12072 1.69277
+3.96494 4.38143
+7.06931 7.89524
+0.514522 1.51265
+6.56389 7.01146
+1.51362 1.8541
+4.90339 5.51209
+2.11422 3.15457
+2.50094 3.92557
+8.24319 8.62826
+-0.0843505 0.710377
+6.35956 7.89457
+-0.790954 1.2964
+4.02253 5.19193
+2.7425 3.46763
+9.41469 10.1367
+1.57636 2.25105
+3.18647 3.38738
+8.36644 9.66791
+0.180846 0.461221
+7.07675 7.71881
+0.265366 1.19275
+5.43007 6.4854
+9.13912 9.23294
+9.52905 10.4029
+1.18712 2.66227
+5.22714 5.62601
+1.87413 2.8716
+5.71882 6.16374
+5.38169 6.13948
+-0.196005 0.236738
+5.36803 6.4395
+8.27713 8.71262
+8.82031 8.8598
+-0.53845 0.564783
+1.80716 1.94173
+5.67905 7.47291
+2.37779 3.64893
+0.574727 0.766424
+4.60701 4.86591
+3.17989 4.37738
+1.36777 3.15112
+1.48092 3.06573
+3.37009 4.06028
+4.17179 6.2073
+6.47953 6.88994
+5.74431 6.5253
+4.88827 5.49049
+5.44148 5.59239
+1.66153 2.63132
+7.69387 7.82267
+5.20911 5.48488
+-0.103218 0.497402
+7.18003 7.33324
+6.54305 8.81732
+0.278108 1.27452
+2.38323 2.94772
+1.2461 2.03246
+5.47052 5.75781
+7.31505 7.35895
+2.22248 4.23589
+0.0305319 0.430773
+8.32043 10.1222
+6.11732 7.09764
+5.08797 5.74991
+6.62491 7.34164
+5.55795 5.66083
+3.27549 4.13145
+1.0113 3.24631
+0.0717186 0.519738
+7.82905 9.30839
+9.90251 9.98691
+0.841457 0.952276
+-0.133927 0.510174
+1.14614 2.82218
+2.59767 4.19742
+3.41095 3.95265
+3.38951 3.75838
+8.86766 9.19437
+9.27927 10.261
+2.33249 2.79402
+5.69681 5.93469
+4.02502 5.38732
+0.797157 1.22845
+7.23558 7.8651
+1.1253 1.99184
+8.58296 8.64267
+-0.400141 0.74698
+3.46677 3.50526
+6.03252 6.64842
+5.8493 6.68938
+3.53209 3.84014
+7.22078 8.98106
+6.21943 7.69944
+0.887198 2.07323
+3.36591 4.57442
+4.30143 6.41179
+4.07556 4.54276
+8.77552 10.0615
+6.7247 7.04044
+9.05494 10.1126
+7.46604 7.80632
+3.38601 3.8043
+5.60475 7.02788
+9.09811 9.4654
+9.33447 9.80012
+8.66499 10.1002
+3.87007 3.88281
+2.87624 3.11359
+5.92385 6.80801
+4.49711 5.01863
+8.84524 9.36225
+6.40944 6.82093
+2.90915 3.68288
+3.96801 4.82534
+5.51744 5.84233
+3.2959 3.44409
+0.18526 0.207322
+5.49717 5.72648
+6.9522 7.1952
+0.769572 1.79343
+5.95522 6.03918
+6.54327 7.7475
+2.13516 3.83957
+-0.388892 0.775076
+1.30128 2.29414
+9.76761 10.1604
+7.38731 8.66002
+7.09229 7.43495
+9.1379 9.52432
+6.75942 7.88717
+7.42824 8.82063
+6.93078 8.19884
+2.307 2.93836
+8.38254 8.84691
+3.90159 5.37938
+0.0413204 0.112203
+0.638217 1.53943
+0.88678 2.49435
+1.99104 2.60847
+6.61595 7.65064
+2.37641 4.71719
+7.94945 9.21404
+5.44594 7.13646
+5.45737 6.12335
+7.39207 8.02885
+5.51588 7.39341
+8.1581 10.0632
+0.197869 1.44516
+-0.0161139 0.73487
+4.24155 4.7304
+0.00374564 1.26481
+8.1878 8.20011
+-0.115544 1.74771
+0.912347 2.52922
+2.72234 4.83268
+6.45577 7.07776
+9.74201 10.1772
+7.11008 8.72914
+4.41921 4.8673
+7.97673 8.36658
+0.438659 0.647061
+4.35086 5.44482
+8.22919 9.34379
+3.53242 5.65576
+1.126 2.32177
+5.95118 6.51364
+3.10519 3.9447
+1.28889 2.26267
+7.04255 7.67791
+3.12614 3.17626
+8.09968 8.49162
+6.07924 7.219
+5.99554 6.52549
+9.14378 9.5773
+5.82872 6.53112
+9.3361 10.1704
+4.3751 6.51675
+3.288 3.98328
+4.56342 4.80185
+7.16574 7.43901
+7.7638 8.47758
+7.31514 7.78499
+7.98942 9.50252
+4.31211 4.70724
+2.9094 3.33304
+0.108736 0.668815
+8.08409 9.11098
+-0.0053985 0.589992
+1.31926 2.72153
+2.28664 2.38813
+7.95237 8.26388
+-0.0283047 0.452099
+7.50295 8.71708
+7.72356 8.63468
+3.48953 3.89579
+7.73814 8.73456
+4.54487 5.45817
+6.45109 7.00312
+3.99915 5.41716
+6.81436 8.5682
+6.86726 7.55999
+2.67863 3.7053
+2.6837 3.39567
+2.84347 2.91724
+5.79383 5.80493
+2.41217 3.0619
+8.78163 9.0998
+1.43456 2.50854
+6.73393 8.53005
+3.02563 3.56456
+3.34628 4.2934
+2.44985 2.92819
+1.38262 2.89341
+4.56337 5.75702
+0.275735 1.16604
+1.39763 2.8108
+9.69128 9.90361
+8.54868 9.66756
+3.01838 3.72831
+8.34017 10.5262
+1.82721 3.0476
+5.9732 6.83307
+2.77874 4.25603
+1.71987 3.1227
+6.33773 7.89103
+1.31982 2.82992
+4.21601 4.9627
+6.68166 6.72653
+0.87708 1.06828
+1.03483 1.26625
+2.996 4.03087
+1.54718 1.57452
+2.33087 2.38226
+2.29464 3.36496
+2.03064 3.41867
+5.8456 6.10406
+7.54614 8.2874
+1.42938 2.89154
+2.65935 3.53883
+3.98845 4.42049
+6.85632 7.15487
+8.12038 9.34993
+0.873558 1.32129
+6.61595 8.00766
+9.49147 9.81947
+-0.0225601 0.328769
+-0.481519 1.37204
+6.31457 7.45251
+4.59738 5.81395
+4.83304 5.63008
+1.95746 2.78657
+2.97889 3.74408
+9.08327 10.702
+3.58219 4.93634
+7.87068 9.77851
+0.330978 1.36031
+4.78145 5.36918
+4.94672 5.56644
+7.66806 8.08613
+4.78512 6.35461
+5.17367 5.74386
+8.65884 9.97088
+9.22053 9.60447
+6.15061 6.58817
+0.0875971 0.541643
+6.45597 7.92002
+0.636824 1.05267
+5.31677 6.12838
+6.51127 6.6731
+0.459551 1.69382
+5.75106 6.41377
+3.68438 4.67415
+9.36302 9.78281
+5.46195 7.99215
+2.55471 2.59231
+-0.0640245 1.33755
+9.36027 10.6198
+2.67955 2.77882
+3.51443 4.10619
+6.83904 7.23692
+2.59553 2.81418
+7.74628 8.95169
+3.86464 3.90067
+3.32377 3.992
+1.43737 2.52191
+3.83927 3.99402
+5.24426 5.35179
+0.833857 1.05277
+8.4062 8.51964
+9.62299 9.66254
+3.55427 5.19048
+1.7003 2.62107
+6.8059 7.49246
+-0.761104 0.773528
+1.37137 1.95048
+2.1222 2.59387
+0.633505 2.04796
+0.605156 1.04336
+7.22842 8.3365
+4.28716 5.28921
+8.14286 9.52015
+7.62467 9.18603
+1.11029 1.81278
+5.05654 5.13597
+0.862653 0.97827
+7.24766 7.92167
+8.80103 8.91467
+3.05841 4.82292
+1.28204 1.55969
+1.58886 2.57874
+0.0537678 1.28837
+8.09303 9.71678
+8.37599 8.85705
+3.18107 4.01971
+6.67019 7.75848
+6.29836 8.21603
+0.86271 1.30358
+3.86126 6.49694
+5.84446 6.24913
+0.475025 0.598151
+6.3477 7.08327
+3.60161 4.51824
+7.13317 8.13858
+4.89052 6.23701
+5.69441 5.99027
+7.18735 8.34853
+9.30182 9.34894
+6.06589 6.15141
+8.05917 8.89642
+5.6136 7.14058
+0.838337 0.959487
+0.56421 2.00841
+6.46876 6.63629
+2.4434 3.92184
+7.97216 9.45372
+8.17926 8.66756
+1.86522 2.01888
+0.983342 1.89079
+2.07322 2.09765
+3.52974 4.73717
+3.24973 4.88691
+5.47789 5.95384
+4.11218 4.57076
+6.61174 7.47165
+8.09302 8.36193
+1.67911 1.69022
+4.436 6.17515
+5.6544 5.74951
+1.50354 1.76043
+4.41433 4.83589
+1.82528 3.53979
+3.98749 4.65527
+6.42503 7.5787
+8.69554 10.1767
+8.39215 8.56999
+8.71646 9.66209
+1.59091 3.39622
+6.12574 6.94955
+7.92527 8.25049
+9.19858 9.49137
+2.73382 2.97747
+4.56558 5.94738
+8.33983 8.58548
+9.00798 9.01838
+4.93268 5.28383
+3.15356 3.58606
+8.28171 8.79351
+1.47358 1.9581
+0.891797 2.05345
+1.56032 2.38159
+2.5152 3.80485
+8.0963 9.88138
+1.1262 1.89279
+7.99336 8.2352
+5.25067 5.41251
+4.57532 5.20101
+1.87911 4.59415
+4.25142 4.70467
+8.18782 8.76989
+9.20478 9.3612
+7.70898 9.7752
+0.655865 0.958924
+4.8883 5.77477
+3.03279 3.47456
+1.01979 1.41661
+8.94219 10.6987
+2.49348 4.58195
+2.44003 3.29005
+3.4725 3.55572
+9.3917 9.95851
+7.08658 7.47686
+3.56413 4.44089
+-0.47868 1.11453
+6.82615 8.00596
+3.49451 3.74705
+8.13286 8.47976
+7.01732 8.82556
+1.19064 1.48887
+5.28851 6.88637
+8.83175 9.49879
+0.939903 1.17024
+7.49124 9.01906
+2.9285 4.23224
+5.68296 6.86273
+8.53897 8.77886
+2.9107 5.01232
+0.748655 1.10265
+4.77258 5.12626
+3.995 4.75289
+2.71467 4.26926
+6.21665 7.16233
+4.53883 5.75731
+4.37153 4.76125
+7.47635 8.75777
+4.82013 6.4699
+9.36015 9.58451
+4.43054 5.86752
+2.10934 2.34705
+3.00306 3.06539
+7.81957 8.44081
+1.97221 3.06916
+0.153393 0.503956
+5.05611 5.27536
+5.73277 5.89001
+3.64807 4.85582
+6.13416 6.1528
+3.85511 4.14045
+0.411725 1.36529
+2.26932 2.5447
+3.51164 4.93266
+2.50955 4.34201
+8.74663 9.39268
+6.2229 6.39303
+4.38059 4.91592
+7.29109 8.62318
+6.31801 6.99532
+9.75036 10.0514
+1.69019 2.41527
+4.20462 5.27729
+6.32944 6.94729
+3.5736 5.21496
+4.48316 4.61828
+1.76915 2.43263
+2.42026 4.09159
+2.08762 2.43074
+5.48161 6.02473
+5.51826 7.47042
+2.78026 3.1552
+7.89469 9.49867
+3.09084 4.54697
+7.20417 7.42408
+5.36528 5.74851
+1.86239 2.41988
+1.55994 2.85743
+4.40182 4.6638
+7.91619 9.01242
+3.08119 3.74714
+1.54108 2.08538
+3.61461 3.64631
+8.76851 9.66257
+-0.645571 1.3366
+-0.707083 1.21005
+7.19571 8.23405
+5.42865 5.89329
+2.12897 2.59222
+0.603102 0.930391
+3.75025 4.63181
+6.14867 6.4526
+7.30947 7.51461
+7.83183 8.79802
+6.06658 8.53246
+1.67895 2.50063
+1.14179 2.04478
+8.59583 8.90112
+-0.918885 1.30717
+0.182607 0.613593
+3.3335 3.77196
+0.783053 2.4368
+6.49331 7.60104
+2.85101 3.28637
+7.42273 7.66905
+3.96433 5.02573
+8.26262 8.40749
+9.24451 9.32783
+4.89036 7.07214
+6.45431 6.96815
+5.20701 6.58747
+7.40142 7.98615
+4.19768 4.9831
+3.32546 3.88811
+-0.471996 0.967855
+9.36172 9.63532
+1.96831 3.00632
+7.537 9.72671
+4.67746 4.81135
+3.10782 4.93642
+4.94809 6.54855
+4.16763 5.25628
+9.04992 10.316
+0.668935 0.680886
+4.02935 4.84503
+5.32499 5.76636
+5.32267 7.15457
+5.18886 5.23491
+4.37053 5.36801
+2.39955 2.74657
+8.19764 8.86645
+4.24706 5.69703
+1.87851 2.36988
+0.886553 1.05064
+7.27428 7.90224
+9.08417 9.44879
+3.11534 4.02019
+6.3284 7.39925
+4.96029 5.59076
+2.58248 3.11741
+7.76513 8.13505
+4.93613 6.51523
+0.565355 1.70512
+2.12366 3.0319
+5.32422 6.84146
+-0.135396 1.08591
+3.7901 4.86303
+4.49677 5.41847
+0.615748 0.834712
+0.64784 1.81859
+6.65505 7.13894
+-1.12744 1.61017
+0.550814 1.24316
+6.66639 6.89866
+6.19271 8.17468
+3.09382 3.78684
+4.41221 4.95889
+7.96091 8.48824
+8.32129 10.2917
+2.13168 2.19835
+1.4635 2.38989
+5.78102 6.42215
+1.70153 3.20616
+5.35068 5.71016
+4.27702 4.37203
+5.13888 6.04764
+4.79644 5.37927
+6.75314 7.66368
+6.04484 6.84064
+4.34947 4.45643
+9.08755 10.396
+0.88804 2.17441
+6.86788 7.88301
+7.94296 8.61664
+8.02387 8.79591
+1.79024 2.40559
+5.50404 6.01044
+7.76772 8.1932
+1.174 1.23693
+6.20571 6.9224
+4.20863 4.48702
+4.16743 4.39075
+-0.11965 0.120778
+7.01234 7.52619
+5.91415 6.46151
+5.28713 5.72354
+6.26981 6.31237
+0.643056 1.43864
+1.62562 1.99875
+0.544992 0.721386
+6.92522 7.09165
+-0.107048 1.12273
+0.644674 0.91244
+8.56904 9.01883
+2.23079 2.56598
+9.79034 10.1123
+8.13788 8.4131
+1.86753 1.95236
+2.97577 3.33272
+8.57454 10.0193
+1.20043 1.53408
+3.43515 3.86571
+5.79075 6.41293
+1.71558 2.52845
+2.39907 3.46652
+9.08289 9.91182
+0.859644 1.07475
+5.30144 5.42157
+-0.441497 0.890794
+3.55044 4.14918
+-0.340115 1.19239
+6.5534 6.76908
+0.836514 2.09196
+8.15747 8.96484
+4.80087 5.14227
+7.72071 8.88223
+5.11901 5.65559
+4.44996 4.63562
+-0.328404 1.3002
+0.90759 1.34556
+5.94839 6.35058
+1.76504 1.78344
+1.32585 2.08994
+7.18641 8.20945
+0.62657 1.06025
+6.28086 6.40975
+5.05525 5.16143
+5.82694 8.07685
+6.23677 7.55394
+-0.226265 0.661443
+1.42599 2.36325
+9.04445 9.92971
+-0.169286 0.185741
+8.34636 10.9042
+9.52494 10.0475
+8.39989 10.1377
+3.89956 4.70428
+3.98673 4.97185
+5.43008 5.67936
+7.76475 7.98591
+4.46895 4.73188
+0.584662 1.54474
+2.12622 2.79994
+1.40578 2.2461
+1.45171 2.02105
+2.05665 3.04611
+2.29818 2.68118
+1.77344 2.98698
+4.92092 5.55302
+7.18758 8.37525
+8.83407 10.0565
+2.91182 4.71932
+6.47293 6.74664
+2.49238 3.69749
+0.487234 0.541003
+4.703 4.92744
+9.8867 9.94918
+1.7713 1.9792
+5.68316 6.90242
+5.62485 6.70656
+7.24837 9.60197
+7.71147 7.76519
+5.22324 5.30661
+9.11258 9.28071
+8.2827 8.90115
+8.90865 9.42138
+7.47233 8.72308
+4.89712 5.65153
+4.12392 4.20239
+5.65325 6.55887
+8.65945 9.05845
+7.9165 8.36489
+1.4952 2.43991
+5.49665 5.80793
+1.67206 2.55302
+0.943544 1.58521
+0.47 0.860959
+6.47638 7.43101
+4.38434 5.97278
+8.12782 9.10574
+5.78143 6.6539
+9.23616 9.40513
+1.6845 2.00736
+6.56955 7.37847
+7.42993 9.04718
+-0.179632 0.450904
+8.65819 9.07724
+7.86567 8.80824
+1.85428 2.7755
+2.29222 2.65374
+4.03614 4.51729
+6.9326 7.07635
+5.50807 6.498
+6.17637 7.26432
+8.7688 9.16308
+7.65 8.88604
+3.74495 4.29991
+8.5671 10.5661
+7.41964 8.21083
+8.04302 9.78783
+0.269663 0.317601
+8.29804 9.40991
+3.90673 4.22298
+8.82384 10.9441
+7.27081 8.19548
+1.30184 1.98993
+8.13028 8.92385
+7.21224 7.35137
+5.02122 5.69666
+0.817219 0.974073
+-0.128067 0.589359
+2.12137 2.74019
+5.24657 5.44714
+1.55805 3.10332
+9.91031 10.0748
+7.13941 7.9143
+-0.183908 0.934079
+3.987 4.11053
+3.26678 3.67608
+9.75921 10.1121
+0.755391 1.06346
+7.28479 7.49982
+1.37522 3.80623
+0.944351 1.46531
+9.49278 10.2372
+8.28946 8.67597
+9.43537 9.58003
+7.73357 8.756
+2.64043 2.8687
+4.70448 6.99929
+3.82199 3.89343
+3.43825 4.10908
+4.42362 5.69086
+8.08536 8.60142
+8.43208 9.31272
+7.5889 8.39208
+7.90112 7.9734
+6.10381 6.80568
+8.76283 8.80151
+1.46728 2.53288
+1.68884 2.47102
+7.63343 8.29838
+9.18852 9.5558
+0.977174 1.4792
+4.7577 5.74873
+4.66433 6.37375
+-0.0952277 0.378184
+5.30929 6.07469
+4.98811 5.16146
+3.0744 5.59799
+0.944909 1.25222
+1.38561 2.51277
+3.77811 4.23459
+2.11604 3.32458
+0.920929 1.17187
+5.23496 6.34905
+6.9953 7.65745
+4.81803 4.89553
+4.69301 5.36777
+-0.208926 2.6111
+7.97334 9.83269
+-0.396673 0.779988
+5.91367 6.47682
+6.27249 6.83533
+5.58931 6.89679
+2.03394 2.67025
+-0.197752 0.383167
+4.69751 7.695
+4.5989 6.07875
+3.7285 4.27396
+7.9807 8.27693
+-0.00248985 1.30934
+2.68016 3.916
+0.881558 1.14567
+4.77066 5.05302
+0.552268 0.919467
+2.46862 2.65199
+1.4009 2.51701
+-0.171185 1.28252
+9.27842 9.90243
+3.51778 3.57728
+6.10071 6.92163
+9.05387 10.0894
+5.52995 5.89082
+8.40216 9.0272
+9.02911 10.1602
+4.85818 7.38829
+1.6762 2.32334
+6.45416 8.62337
+5.44592 6.0245
+3.45876 3.94274
+9.07144 9.16725
+6.51885 7.6363
+7.92593 9.01986
+0.270702 1.57395
+6.11245 6.70173
+1.37658 2.19068
+2.42668 3.43827
+7.98226 8.43306
+3.72269 4.74654
+8.16252 8.58873
+8.81456 9.5363
+-0.338386 0.864811
+1.90693 2.25796
+3.5305 4.17475
+6.07997 7.67393
+0.53347 1.68815
+7.31182 8.44458
+7.77462 8.33613
+3.79975 4.15552
+9.08822 9.9771
+-0.101698 1.05442
+8.44869 9.95724
+-0.0318759 0.532673
+8.09238 9.51356
+5.51514 6.60799
+8.66528 10.3297
+8.25556 9.97893
+-0.220428 0.247563
+0.00453913 0.540444
+1.53599 1.61735
+3.77213 5.06896
+2.65332 2.75864
+6.05811 6.43112
+0.302534 0.803651
+0.393766 1.11611
+9.31035 9.62387
+0.568281 1.7765
+-0.721118 1.27387
+1.83573 2.62578
+1.39953 1.91158
+6.51883 8.52813
+2.60154 2.95054
+6.58322 9.37818
+5.61178 5.67661
+9.56511 10.2767
+9.09174 10.0697
+2.55846 3.39943
+8.38146 9.06138
+7.97019 8.18074
+6.1426 6.42787
+1.15876 1.55463
+2.93483 2.96376
+7.23883 7.29158
+9.64606 10.0674
+4.89825 6.70366
+7.35635 7.96328
+2.2702 2.36797
+-0.0464389 0.395244
+1.14883 2.10411
+4.7309 5.10593
+6.07946 7.37741
+5.50202 6.28822
+3.66574 3.96271
+1.9944 2.3862
+7.58159 7.59275
+1.98712 3.30587
+2.10317 2.89161
+9.66889 9.97287
+1.57327 2.15421
+8.14125 8.30983
+3.77185 4.12658
+8.51624 9.51485
+9.25211 9.722
+2.06312 3.0453
+9.34954 9.91254
+7.31475 8.89322
+7.85044 9.20242
+0.226243 1.28465
+0.0260868 0.575177
+9.40743 10.1655
+4.04324 5.05341
+1.02626 1.48332
+3.33074 3.72025
+9.2005 9.61387
+6.68317 7.14109
+6.82083 8.6312
+4.34816 4.50329
+-0.48874 0.975608
+4.26651 5.68526
+4.89731 5.57569
+2.68984 3.5661
+0.499714 1.01055
+9.01902 9.36142
+3.22067 4.59054
+0.65132 0.860512
+1.6791 2.36642
+8.28222 8.7579
+2.84349 3.24134
+5.64949 6.09512
+3.44026 4.43245
+2.60889 2.6248
+-0.00849234 0.984046
+7.5745 8.65675
+2.07464 2.6488
+2.59747 2.65772
+6.36828 7.42208
+3.83342 4.50127
+5.41167 5.7011
+6.53606 7.53796
+8.21975 9.56176
+1.90113 3.08684
+7.74402 7.82057
+4.26515 5.11327
+5.42743 5.59215
+8.69709 10.0912
+2.87019 3.94798
+9.27013 9.54627
+9.30568 10.2136
+9.02985 9.62917
+3.7589 4.59642
+6.59359 6.86939
+3.26574 4.83488
+5.14545 7.70086
+7.43163 8.05103
+5.72972 5.74457
+0.490113 1.31151
+7.018 7.42627
+6.22976 6.27589
+9.07732 9.30419
+4.3917 4.42663
+8.50298 10.3728
+6.18671 7.53619
+3.51053 4.097
+2.17172 3.56595
+6.08046 6.23691
+9.07361 10.9129
+3.95757 4.11333
+-0.136516 0.78995
+1.34923 3.47002
+0.0562579 0.686502
+9.10943 10.2731
+5.80174 6.16971
+7.86011 7.87649
+5.34384 5.51645
+6.32167 6.76387
+7.70566 8.28038
+-0.319903 0.867682
+-0.372564 0.570014
+8.83696 10.8439
+7.78947 9.38211
+9.25815 10.1092
+5.59721 5.67148
+0.234719 2.42489
+1.06314 2.87416
+1.75391 2.69799
+5.4536 6.66068
+1.35696 1.87102
+2.17418 3.1459
+7.61817 7.98287
+2.92194 3.18393
+7.68243 7.83261
+9.33163 10.5531
+1.14227 2.50228
+5.47911 5.70857
+9.88123 10.0758
+8.81249 8.83145
+6.02747 6.43183
+4.81158 5.79178
+6.65666 7.5047
+4.89085 5.56569
+0.935564 1.71547
+-0.0452879 1.16222
+4.03524 4.6206
+5.88518 6.02658
+2.06227 2.9581
+0.207246 2.2404
+2.81757 3.70318
+0.704257 1.98403
+2.38486 3.30039
+3.57073 4.78358
+1.53721 3.00546
+8.37852 8.39527
+1.54619 1.59789
+1.00447 1.40778
+5.31977 6.43861
+3.82175 3.83209
+3.37738 4.44002
+5.46644 5.97254
+3.88191 5.00688
+4.88046 5.39031
+4.15092 4.93679
+1.75182 2.07399
+1.16434 1.76541
+3.37032 4.29676
+3.1685 3.98533
+1.28787 1.59775
+5.86338 6.17993
+3.8645 4.25757
+1.83947 2.48092
+0.184795 0.586724
+3.13752 3.76447
+2.14264 3.03248
+5.78182 5.9029
+2.47969 3.8088
+2.59206 3.08362
+-0.354871 1.03627
+7.94041 8.05947
+9.48014 9.93817
+0.992727 1.48877
+6.1525 7.51387
+5.00071 6.15665
+7.42074 8.27606
+9.6539 9.83042
+1.08984 1.46387
+5.46282 6.95907
+4.74506 5.13968
+0.357565 1.91464
+9.07652 9.65474
+0.201095 0.646211
+7.04306 7.69131
+1.17728 1.2237
+5.92183 6.29165
+-0.41356 0.491524
+8.38339 10.4509
+8.08648 8.11344
+3.32474 3.39522
+5.762 5.83732
+2.26778 2.55548
+4.86127 5.92868
+3.75949 5.16608
+4.83431 5.88632
+2.65122 3.31344
+9.30295 9.38948
+6.03391 6.32749
+5.12035 5.59414
+5.68785 5.979
+7.89553 9.15202
+2.54445 2.74715
+2.36337 2.49709
+4.71661 6.12198
+3.72447 4.68735
+1.0541 1.53187
+3.45178 4.80929
+7.90773 8.26212
+8.1816 9.18627
+0.322569 0.871041
+7.24823 7.32699
+1.7003 2.78087
+9.70927 10.2515
+3.75922 4.01081
+1.06949 1.40253
+1.21774 1.4734
+6.02123 6.32973
+2.76396 3.09484
+2.80358 3.00026
+5.25666 6.31369
+4.71714 5.30669
+4.37906 4.50557
+7.40824 7.44969
+7.89081 9.18263
+8.8136 10.3074
+9.1757 9.37261
+7.1938 8.51137
+0.580081 2.32678
+2.02497 2.95434
+6.01446 6.78851
+8.54365 9.21454
+3.03567 3.27089
+0.650657 1.5716
+5.05518 6.36521
+1.64301 2.76399
+4.15989 4.34183
+3.72791 3.98156
+3.91372 4.06182
+3.04507 3.88871
+3.82596 4.25694
+3.36492 5.00402
+6.50019 8.17974
+3.54621 3.81009
+0.546921 2.09811
+5.1789 5.9826
+4.98983 6.31221
+2.47557 2.63878
+4.64568 4.81101
+9.1462 9.21888
+7.37417 7.5276
+2.21604 2.50113
+8.29804 10.2722
+5.1282 6.06353
+8.58281 10.1589
+6.47084 7.04085
+6.27806 6.72674
+7.11554 7.85687
+6.01085 6.02773
+5.46694 7.52872
+9.51078 9.85387
+3.36627 4.06552
+2.96126 5.12635
+3.09314 3.40691
+5.05456 6.62548
+7.56469 8.97053
+1.33727 2.87482
+5.6572 6.28169
+0.120924 0.296475
+7.09139 7.41322
+2.10076 3.28507
+8.74998 10.1094
+7.45072 9.50796
+7.75294 8.59218
+0.740374 2.44897
+7.63001 8.91562
+4.30743 4.81716
+6.40813 7.29159
+6.30213 7.35987
+6.44392 7.32584
+8.41155 9.4466
+-0.377892 0.689618
+5.88857 6.70983
+6.67779 7.70668
+4.831 5.17464
+2.62342 3.82764
+8.57453 9.29283
+7.32648 7.96725
+9.32937 9.9726
+7.30774 7.65754
+3.97456 4.59876
+5.73092 7.20962
+1.958 2.10551
+3.2115 3.81482
+5.76497 7.42425
+2.77219 3.29692
+4.95297 5.14843
+5.96367 6.3619
+2.49872 4.61736
+8.21817 8.23425
+2.13615 2.61877
+7.84121 9.55011
+8.63416 10.2773
+5.61084 6.32053
+4.86002 5.79944
+9.07858 10.688
+5.95829 6.42504
+3.3289 4.17849
+3.27989 4.91625
+8.28046 9.23021
+2.18691 2.6072
+1.3962 1.75013
+2.13627 3.73117
+2.11128 2.57303
+7.22357 7.50136
+7.43862 8.03136
+2.80578 3.02886
+0.176906 0.761142
+5.99314 6.6075
+1.90398 3.3925
+5.48264 6.73579
+7.18447 7.49811
+3.24434 5.05219
+5.53263 6.04178
+1.71172 2.45682
+0.297266 0.481632
+2.62582 3.36142
+0.243865 1.49321
+8.86142 10.169
+3.93193 4.39404
+4.98182 5.15675
+7.99209 9.73159
+8.18033 9.45596
+4.25235 4.41546
+1.59603 2.15581
+6.47724 8.69649
+5.24138 7.93131
+3.4267 3.49003
+0.0439912 0.316407
+1.99983 3.87206
+-0.103124 0.568771
+4.62451 4.80117
+2.89065 4.16315
+5.82817 7.43232
+6.89255 7.82189
+5.71037 6.81241
+4.34551 5.24905
+7.33931 7.3741
+-0.855192 1.27129
+8.94842 9.10813
+9.19877 9.68412
+6.42658 7.77968
+-0.0669636 0.430107
+6.40366 7.40701
+8.91175 9.24059
+3.21388 4.21676
+3.38557 3.79509
+4.24411 4.97032
+7.259 7.34896
+2.55995 3.18361
+8.77438 10.5503
+8.18685 9.79378
+2.78397 4.4563
+8.6891 9.38337
+6.51749 7.59374
+2.52346 3.46101
+8.40526 9.35647
+5.26942 6.33572
+4.15094 5.00668
+0.471666 1.53842
+7.63441 7.96745
+2.39974 3.7814
+2.71989 3.02994
+8.12085 8.33493
+6.19474 6.84381
+6.6133 8.31417
+5.1758 6.94983
+8.66241 8.79095
+6.10878 8.22083
+8.81883 9.08031
+8.28969 8.45176
+7.19851 8.37836
+1.5722 1.6836
+4.57814 6.95063
+7.66128 8.10631
+0.742483 3.08515
+1.15026 1.98074
+3.90133 4.12003
+7.61145 7.73433
+8.32187 10.2933
+0.407205 1.08089
+1.26545 2.60796
+2.70646 3.92753
+-0.196551 1.83536
+-0.413063 1.23838
+0.264484 0.556192
+6.30158 6.96097
+-0.66246 0.809062
+9.34243 10.3521
+8.70093 8.79679
+0.745195 1.92911
+9.12892 9.68193
+7.98533 8.30538
+6.23671 7.04296
+6.5603 6.95483
+7.08133 7.10563
+2.15769 2.41541
+8.24752 8.73978
+5.27693 5.61904
+0.317419 1.48404
+3.48029 5.46979
+7.38901 8.56554
+1.06587 1.62384
+5.54926 6.04924
+4.46577 6.48749
+5.349 6.15584
+8.04249 8.17359
+3.37651 3.56179
+3.64706 5.57403
+4.49844 5.26404
+3.93361 4.92128
+5.82184 6.29881
+0.984273 1.70318
+1.12773 1.80726
+3.11675 3.17451
+5.07913 5.46291
+0.615591 1.81465
+1.08948 2.77847
+7.97412 8.07365
+5.05207 5.82497
+0.0407709 0.558817
+6.11142 6.48205
+3.4461 3.57315
+8.6547 8.80553
+8.18965 9.64194
+5.55564 7.9703
+4.01776 4.16989
+2.4668 2.82018
+0.911925 2.56662
+4.68814 5.03614
+7.4899 8.49036
+8.40912 9.14001
+2.32725 3.16377
+0.0723972 1.42049
+6.6441 6.6953
+3.65586 4.38222
+6.35844 6.57833
+4.44435 5.73077
+1.81779 2.57257
+4.17692 4.59722
+8.54682 9.38058
+1.61135 1.81629
+3.91926 5.00536
+9.78302 9.85143
+1.25632 3.10345
+5.53191 6.08174
+-0.231868 0.676811
+1.03054 2.58105
+0.0402172 0.690608
+0.974571 1.25234
+5.22227 5.92302
+8.05843 10.1439
+8.48938 8.50755
+0.0965782 1.24008
+6.53821 7.47765
+0.189991 0.475204
+8.48963 8.54995
+9.68363 10.0534
+1.49381 2.71302
+6.75552 7.41283
+7.91075 9.15302
+0.520922 1.40928
+1.17957 2.11221
+4.00122 4.40686
+7.32467 7.9273
+6.39126 7.90248
+6.50534 8.19308
+7.19888 7.22234
+-0.136797 0.731889
+0.870318 1.25614
+2.07126 2.28297
+6.10995 7.60408
+3.02174 3.90102
+-0.657541 1.57517
+0.993121 2.66255
+7.27232 7.50832
+2.16079 3.75428
+9.27397 9.75098
+8.36865 8.5545
+4.56641 4.97607
+3.60746 4.34616
+6.31304 7.70611
+2.91442 3.7602
+4.85814 6.70407
+4.45876 5.67661
+8.06749 8.82229
+2.02826 3.59873
+1.92922 2.50088
+2.63867 3.48117
+2.17665 2.54826
+8.62674 9.10675
+0.96648 1.47671
+8.86336 9.53978
+5.52747 5.80829
+0.77099 3.06106
+2.2307 2.53877
+6.29165 6.63018
+4.44717 5.04651
+3.80894 4.63054
+7.47519 7.87072
+0.933668 1.9949
+-0.712945 1.21558
+7.30206 8.38376
+5.80281 7.00022
+7.96578 8.6558
+0.24063 0.706466
+4.41893 4.58472
+4.0132 4.92768
+5.29626 6.09397
+3.43602 4.00728
+0.780945 1.66499
+8.83861 9.15168
+9.06411 9.75544
+3.45618 3.62529
+9.51413 10.0148
+0.842106 1.75695
+1.06485 1.44192
+6.89987 8.05314
+7.89154 8.73313
+8.71675 9.79526
+2.40574 2.58062
+8.55952 8.78132
+5.61716 6.06282
+3.71059 3.77929
+2.50187 2.99137
+6.92852 7.23184
+7.00442 7.93869
+8.82232 8.8756
+4.10389 4.53702
+7.6907 7.77577
+9.31554 10.2674
+8.51082 8.70339
+4.83332 6.70311
+4.6904 5.42892
+4.71407 5.67695
+4.12047 4.44089
+7.51845 8.26858
+1.31781 1.9397
+6.26854 8.02093
+6.92072 7.77774
+0.438156 2.18909
+0.898035 1.72074
+3.81121 3.8643
+1.01676 1.34308
+9.28445 9.42801
+2.43133 4.43516
+4.33664 5.9904
+2.19178 2.37244
+1.5457 1.79785
+2.23781 2.6481
+6.8365 6.87073
+0.82568 2.74775
+9.59404 9.89262
+8.48394 9.15107
+6.16085 6.42224
+3.5667 5.97689
+4.16931 7.41638
+6.95636 7.0982
+6.87987 7.09233
+3.12619 3.14821
+7.76636 7.98459
+4.60371 5.59136
+3.92189 4.88302
+6.90694 8.19858
+3.85132 5.19015
+8.05045 8.32483
+4.8338 6.05032
+1.93576 3.18873
+2.4182 3.55039
+5.56905 5.8172
+4.18436 6.01283
+3.04944 3.85936
+7.83585 8.95233
+1.76281 3.0558
+3.44143 3.6317
+8.69887 9.40371
+5.67867 5.73236
+0.859809 1.76578
+6.92284 7.13601
+8.27495 9.13414
+5.44385 6.42599
+-0.941603 1.8215
+7.88161 8.79447
+0.965018 1.17732
+5.56442 5.79546
+8.79032 10.9909
+5.28632 5.79175
+4.80998 6.07002
+8.4021 9.81107
+3.16415 5.08682
+-0.212163 1.2052
+5.683 5.83625
+0.738527 1.31842
+2.03835 2.52756
+7.4543 8.91243
+-0.568869 1.44659
+3.58855 4.42371
+6.33058 7.18779
+-0.645579 1.94313
+2.18149 2.24157
+3.80281 4.67323
+5.14628 5.97452
+2.55239 3.45685
+3.56586 6.23355
+6.74752 7.19693
+8.99006 10.5533
+0.259833 0.99882
+8.9005 9.75401
+7.28058 8.41075
+4.57803 5.70104
+9.82823 9.90251
+6.94375 7.42033
+7.8878 8.81951
+5.01137 5.52693
+2.25503 2.28817
+6.65772 7.11107
+0.647512 2.04416
+4.34796 4.5706
+4.5395 4.91529
+2.65423 3.49531
+7.97384 8.78377
+5.53873 5.76806
+9.78641 10.1351
+6.01664 6.44407
+3.47406 3.75187
+4.59421 4.81804
+1.20641 2.00488
+2.48904 2.80768
+5.77372 6.10692
+2.49363 3.24499
+1.8483 2.62965
+2.28556 3.22209
+3.17819 4.51426
+3.5548 4.23276
+3.25239 3.57895
+0.613317 2.44862
+3.82234 4.78976
+4.72809 6.46528
+9.54107 10.4426
+9.20052 10.1921
+8.24152 9.89817
+5.17594 6.19462
+7.83364 8.17082
+5.67992 6.36464
+8.9943 10.1426
+2.20598 3.0081
+3.38199 5.16464
+0.599928 1.35804
+0.841211 1.60761
+5.29338 5.89919
+1.11061 2.29219
+3.41512 3.95907
+7.9375 10.0203
+8.73852 9.66917
+9.95092 10.0162
+4.02544 4.30219
+4.1461 5.37827
+1.08089 1.59196
+7.87513 8.21121
+7.85673 8.0973
+0.96237 1.56519
+2.45532 2.61678
+6.1829 6.23637
+0.135135 0.613518
+3.18324 3.78587
+5.64796 7.20194
+0.861169 1.71661
+9.66005 10.1169
+0.880774 1.12452
+1.29389 1.57658
+5.60299 5.89759
+5.53642 7.07306
+0.540268 1.31836
+6.60244 7.98105
+4.21877 4.57159
+3.15367 4.75356
+7.81055 8.40378
+8.00942 8.10861
+5.78071 6.35646
+3.15993 4.99293
+2.36526 2.78444
+8.1361 8.76071
+1.40066 2.96474
+-0.17906 1.05877
+5.94933 6.6808
+3.43187 4.05553
+3.02912 4.68942
+2.1506 2.29413
+2.3516 2.38305
+2.87496 3.0851
+6.71294 8.99858
+3.76177 5.52545
+1.58417 2.57063
+2.74646 4.27445
+5.48407 6.60696
+-0.133321 0.716559
+3.53886 3.58196
+2.28729 2.40198
+-0.209646 1.21263
+6.62795 7.32318
+0.714781 0.880466
+2.96831 4.05932
+6.00935 6.38896
+5.39798 6.11983
+8.47679 9.70468
+1.4339 1.74845
+2.35223 4.75732
+4.31357 4.9642
+5.26493 7.70538
+7.91888 8.94851
+6.51439 7.69469
+7.69015 7.85411
+3.94274 5.15373
+6.25852 7.32402
+2.73567 3.43236
+7.09564 8.42242
+2.55932 4.29066
+1.79489 1.84559
+8.86427 9.35669
+7.23854 8.27062
+7.8488 7.98307
+0.710888 2.22424
+0.0413624 1.10578
+1.54302 1.97696
+1.64924 3.01081
+8.15535 10.2397
+0.305662 1.63835
+8.20375 9.03123
+1.66617 2.08748
+4.01691 4.88505
+3.32856 4.10709
+5.15342 5.44616
+5.80751 7.38872
+0.485341 1.07648
+3.98267 4.20211
+6.96867 9.37655
+9.48055 9.85181
+8.39277 9.50424
+2.47589 2.79873
+3.48046 5.37417
+4.98279 6.01686
+1.29845 2.31199
+-0.204348 2.50289
+0.23488 1.00378
+6.26899 7.14823
+4.62903 5.49672
+0.199052 0.822066
+6.97297 7.69083
+4.23783 4.65198
+0.530497 0.839143
+6.61355 8.22831
+-0.0103941 2.16307
+0.148601 1.20044
+0.314438 0.67632
+3.43415 4.06208
+1.95498 3.25728
+4.23094 4.84942
+9.5493 10.0057
+2.64964 3.52073
+8.21388 9.1622
+-0.112496 0.47622
+7.97551 8.19546
+2.16155 2.6289
+0.38442 1.46032
+3.85675 3.91557
+1.00605 1.42016
+2.4853 3.53086
+-0.0765625 0.504366
+8.11302 8.46334
+7.18135 7.80218
+6.46466 8.12336
+3.75968 5.33954
+9.08789 9.73677
+6.47459 7.49454
+0.90148 1.47681
+3.44733 3.54163
+7.32968 7.909
+1.30055 2.75407
+8.78735 8.92461
+8.21764 8.59414
+0.888162 1.08404
+5.65195 6.26421
+6.23881 7.33284
+8.69731 9.88088
+3.55695 5.36909
+6.49248 7.02755
+2.31407 3.01952
+5.7803 6.1286
+6.30415 8.01577
+7.73864 8.27496
+0.741078 1.69184
+4.94671 5.68254
+3.28226 5.02894
+1.97446 2.60413
+3.26555 5.54754
+2.56179 3.41897
+3.20058 3.32486
+6.96915 7.69055
+6.89302 7.39856
+1.9659 2.61404
+1.31107 1.36867
+6.23573 6.33677
+0.17616 0.517772
+8.55548 8.79155
+9.61632 10.2651
+2.20331 2.34017
+6.93195 7.42939
+1.25398 2.23119
+1.06577 1.41048
+5.99156 7.09818
+3.34821 4.1271
+4.61618 6.90956
+2.30853 3.52875
+0.0518063 0.113732
+5.38513 6.09734
+1.73468 2.64838
+7.24679 7.63999
+4.18175 5.06728
+7.09602 7.13414
+9.06191 9.11605
+6.2309 7.67675
+3.96576 4.63237
+-0.552645 1.37948
+5.76964 6.89903
+4.9272 7.5832
+4.59003 6.49719
+4.12281 6.9664
+5.12256 5.58387
+1.78859 2.76954
+4.36808 5.05712
+8.41165 9.54483
+8.11513 8.43405
+8.42016 9.52715
+8.50598 9.34564
+1.80028 1.83558
+8.08502 8.43726
+6.96667 8.12021
+5.4726 6.26772
+7.1141 9.29989
+7.83324 8.1744
+8.74368 9.16491
+2.5515 3.01706
+5.92375 6.44495
+7.45628 8.41582
+9.04829 9.71503
+4.58856 4.75356
+7.26064 7.32462
+1.81695 2.40529
+6.88067 7.95052
+1.91408 2.02663
+1.32005 1.45025
+7.47733 8.42004
+4.99403 5.85297
+0.95744 2.28875
+-0.089503 0.536888
+1.09978 2.48865
+1.9959 3.098
+0.376116 0.448329
+3.98908 6.49684
+9.10178 9.51012
+5.41394 7.31529
+6.60708 7.59071
+4.38466 5.76203
+1.84355 2.60304
+0.658705 0.933522
+6.98725 7.05509
+5.60064 6.98804
+1.0603 1.1521
+4.06192 4.46156
+0.351018 1.00807
+9.17113 10.2192
+6.71641 6.74659
+8.85392 10.5272
+4.50816 5.22908
+1.13934 2.43196
+3.3746 3.57576
+7.62137 9.3234
+6.93482 7.16058
+5.66506 6.44324
+5.13364 5.86068
+1.97257 2.03803
+2.69746 2.73067
+0.989591 1.38342
+4.18819 4.69676
+4.31608 5.12265
+2.79556 4.87763
+3.55387 5.34421
+-0.112466 0.585639
+2.43156 2.70221
+5.88314 7.08322
+-0.450332 1.29858
+1.22202 2.46588
+6.74433 7.32925
+5.14596 5.37435
+6.76754 7.41799
+1.48762 2.45958
+4.57241 5.3382
+4.17465 5.02296
+6.48856 7.5576
+0.383566 0.823394
+8.50875 9.08734
+1.79393 2.24548
+5.06812 6.49508
+3.55364 3.61502
+5.58973 6.58885
+0.631097 2.10041
+0.323995 0.941782
+8.8798 10.1036
+6.37114 6.88202
+6.9393 7.83288
+3.09503 3.41759
+3.65269 3.70305
+5.61676 5.8924
+1.90199 2.38446
+4.23683 5.35609
+9.18649 9.88878
+8.28736 8.37734
+3.04805 5.03593
+8.02926 8.38975
+3.58161 4.01331
+3.20923 3.48207
+6.85118 8.78281
+5.06518 7.49843
+1.57456 3.05552
+3.0154 4.23782
+2.83557 3.24854
+1.29358 1.89328
+1.42911 2.72661
+3.17067 3.96651
+0.353554 1.48472
+3.46227 4.25611
+6.17639 7.24657
+5.60878 7.13562
+4.11129 5.52476
+9.17596 9.4123
+3.08339 3.65766
+4.083 4.63013
+0.628465 1.92141
+7.81989 8.39386
+3.35589 3.87531
+5.35974 5.41743
+4.48321 4.64376
+0.888177 1.37343
+8.49061 8.50063
+5.09078 6.01801
+9.65314 9.99342
+1.60502 3.0115
+1.37928 2.77642
+6.60322 8.94046
+6.74573 7.45157
+-0.291156 0.325249
+6.1518 6.66827
+5.38199 6.46959
+3.50128 5.22692
+1.31774 1.70159
+0.550546 1.48845
+7.51187 7.85496
+4.2014 5.23193
+3.88255 3.97209
+2.60555 2.84958
+5.15706 6.00036
+2.99284 3.27867
+0.395077 0.768383
+3.30863 3.60594
+0.0325231 0.379208
+6.55183 7.33346
+1.44554 2.95846
+0.245421 1.29751
+3.98808 5.41226
+5.90242 6.266
+4.11097 5.02597
+0.134753 0.929866
+0.609287 1.16311
+0.231832 1.06825
+6.22093 7.05584
+9.18429 9.80637
+0.544139 1.30185
+1.69143 2.90306
+6.75109 8.67893
+5.49641 6.76104
+8.91712 10.0271
+7.09126 8.12404
+8.82958 10.2847
+0.569249 0.69421
+3.59288 5.8053
+9.25068 9.4226
+8.51607 9.26259
+5.00906 5.17068
+1.83467 2.99102
+7.32006 7.64842
+0.405532 0.603773
+6.41882 6.60495
+0.721592 1.44375
+2.78393 4.46732
+7.14806 7.16117
+5.12868 5.27918
+2.74138 3.1737
+2.95394 4.26547
+7.82827 8.21028
+9.06982 10.7279
+0.108376 0.290131
+6.34574 6.97141
+4.39022 5.50801
+7.98339 8.79674
+3.80026 4.71831
+5.43594 5.66916
+1.6743 2.61476
+4.29763 5.47402
+7.95714 8.69311
+3.4152 3.7387
+8.01715 8.8941
+6.53723 7.44437
+-0.0222108 1.04503
+4.96242 6.01648
+1.70885 1.75511
+7.62434 8.53526
+6.82863 7.39782
+8.19967 9.22283
+1.99719 2.11323
+-0.0124079 0.240201
+4.48577 4.87935
+2.586 4.41666
+6.37848 6.67092
+4.39606 5.67983
+9.39761 10.1095
+7.10866 7.15796
+3.91993 4.52129
+5.10552 5.36997
+7.08963 8.32694
+9.12669 9.58509
+9.26894 10.1974
+0.737413 1.26523
+2.77833 5.28516
+3.19039 4.36857
+4.32954 5.45614
+4.98069 5.49295
+7.54745 8.76142
+5.70425 7.05749
+-0.250513 0.36578
+4.76997 5.89607
+2.03075 2.32111
+6.54141 6.55896
+4.19799 4.45091
+8.7796 9.11915
+5.75014 6.05646
+5.36885 5.42775
+-0.00433056 0.865304
+3.65169 5.4751
+0.23625 0.872926
+0.0386337 0.792214
+4.40245 4.56789
+6.44567 7.42162
+5.51394 5.98005
+3.50146 3.83147
+8.47573 9.85647
+7.91378 8.47044
+9.44297 9.90241
+5.962 6.68782
+4.49034 4.86927
+2.17774 3.47061
+8.80614 9.26595
+7.92096 8.13838
+7.80209 7.93317
+7.78915 8.29735
+6.98111 7.162
+0.491059 1.14901
+8.97965 9.38792
+3.30207 3.53207
+3.17127 4.43581
+3.97564 4.43746
+6.79008 7.17877
+5.61669 7.51263
+4.0853 5.38748
+4.42181 6.32041
+8.08599 8.9095
+2.46938 2.55499
+1.20692 2.06351
+1.98995 2.35216
+8.17116 9.17158
+7.53414 8.37086
+3.7744 4.46197
+3.29464 4.38
+7.33246 7.81959
+4.89572 6.2831
+-0.152496 1.56427
+0.636242 0.938556
+5.62066 6.06096
+9.42994 10.473
+8.95446 9.46311
+0.277891 2.80311
+6.92968 7.29845
+2.75677 3.02975
+2.2859 2.51308
+2.96683 3.03857
+6.44584 6.49518
+8.33607 8.60407
+7.20303 7.7616
+7.07205 7.46849
+2.35677 2.7904
+5.86404 6.12906
+2.42371 4.62735
+3.27237 4.11016
+0.0668578 0.644021
+6.77371 7.45187
+3.66596 5.21874
+0.718034 0.755944
+6.06162 7.05
+6.91473 7.09753
+5.0749 6.08914
+0.759874 1.11978
+8.54591 9.64997
+3.97266 4.70679
+1.51133 3.17164
+7.21772 7.69877
+8.00719 8.37052
+0.284003 0.38001
+4.08842 4.16227
+5.04461 5.79973
+4.60604 5.31979
+2.2461 2.28157
+6.25631 7.69766
+9.12404 9.67586
+7.73134 8.98923
+1.0513 1.46408
+9.17225 9.42567
+3.66795 4.29168
+8.84403 9.28497
+9.93613 9.94729
+3.16615 5.09374
+-0.149675 1.43397
+2.30855 2.48392
+0.843172 0.951801
+8.32945 8.8506
+8.97012 9.94697
+2.8559 2.92359
+-0.321715 0.89173
+7.48565 7.71775
+1.44301 1.47795
+6.6649 6.76187
+9.10721 9.93599
+1.82207 3.03935
+3.61893 4.5306
+2.53746 3.81243
+0.424528 1.29026
+9.51874 9.68841
+7.94954 8.14396
+7.49282 7.52655
+3.04604 3.69656
+9.45461 9.47212
+7.69209 8.16412
+0.607135 1.16564
+0.150291 0.450632
+3.28914 4.01085
+5.45597 6.02921
+8.16157 8.36605
+9.76573 10.2325
+0.151994 1.07074
+1.3748 1.68548
+2.29854 2.63593
+7.92162 8.68895
+1.28795 1.61949
+7.85469 8.26683
+4.32268 6.33174
+6.13964 6.3596
+1.25714 1.88002
+2.05006 2.28294
+8.31864 8.34151
+9.0613 10.0715
+-0.041568 0.25139
+6.79984 6.81686
+5.10674 5.70583
+5.92937 7.01652
+7.57649 8.05834
+0.937157 2.25362
+7.48567 7.59746
+2.33403 2.88942
+7.3805 7.73421
+5.586 5.75327
+0.828854 2.12988
+8.22741 8.59954
+9.69214 10.1207
+6.55359 7.08114
+1.85342 2.634
+6.08756 7.28893
+6.34993 6.93474
+8.93548 10.1463
+5.49445 5.8338
+1.47951 2.14646
+2.62089 2.75888
+2.35352 3.10539
+4.98774 5.28931
+4.92239 5.40697
+7.52674 8.78948
+4.52451 4.83819
+5.45854 5.75838
+5.51553 6.3901
+4.82905 6.44407
+6.20655 6.4483
+5.68116 7.06109
+7.97301 9.15827
+8.8854 9.91623
+9.60198 10.2449
+1.93322 2.67684
+0.441852 1.87646
+5.19981 5.71385
+2.54799 2.5809
+4.34591 5.02655
+7.54678 8.75202
+6.1496 7.19033
+1.13658 1.30756
+1.38724 2.08252
+2.13624 2.30419
+8.49196 9.41369
+-0.21387 0.685093
+2.47875 4.19982
+3.69093 4.00543
+5.70643 6.50331
+7.07443 8.83588
+6.85756 7.68937
+1.69241 1.83242
+0.140565 0.502156
+2.15007 3.23784
+4.97403 5.69757
+5.08315 6.25554
+3.45026 4.01942
+3.37482 4.73009
+7.4154 8.34013
+6.95399 7.59768
+8.07995 9.86199
+8.43993 8.88645
+7.66844 8.12742
+-0.0200687 0.435846
+4.47984 5.9416
+7.66804 10.0801
+4.14578 5.98717
+0.256533 0.89254
+6.43216 7.4474
+3.60295 4.79419
+3.90129 4.29812
+5.30606 5.58674
+9.11552 9.79229
+5.60702 5.85299
+2.39514 2.64865
+4.51164 4.60227
+6.31154 6.77441
+3.12239 3.13505
+7.50962 7.89478
+3.90928 4.88831
+9.64625 10.0629
+5.9465 6.02877
+2.08554 2.10477
+0.087547 0.34748
+2.34295 2.53703
+6.846 7.3043
+1.37869 2.11446
+4.03371 4.26278
+5.38623 6.40917
+4.75848 6.25417
+6.03478 6.15991
+-0.585543 1.2091
+2.52824 3.57712
+3.95687 5.40914
+4.42955 4.71909
+2.9328 3.98848
+5.40471 6.97056
+7.64789 9.30279
+6.19595 7.07492
+8.27328 9.41596
+8.29855 9.13665
+2.54035 3.10488
+8.25038 8.87903
+5.66599 5.88701
+7.40067 8.71195
+6.63762 6.67694
+-0.0163105 1.72666
+4.77743 6.60356
+0.567991 1.14977
+5.96841 6.42987
+3.02266 4.58424
+6.72121 7.35492
+7.51477 8.65223
+8.55055 8.81014
+5.59759 5.82816
+0.218944 1.82542
+1.03197 2.36652
+7.84302 9.1594
+2.11542 4.7332
+6.37618 6.92981
+1.34963 1.59353
+0.516281 1.08859
+-0.0151152 0.0624718
+6.45603 7.23063
+4.76865 5.46588
+7.5893 8.42021
+1.04534 1.99034
+2.62638 3.04997
+5.00254 5.98512
+7.7588 9.44547
+6.82186 7.34321
+8.7629 9.82272
+-0.309554 0.54858
+4.19843 4.92981
+5.62327 6.80846
+6.40599 7.6073
+6.1547 6.53898
+3.93941 4.44985
+3.28342 3.72778
+7.17256 7.23035
+2.31269 3.05437
+7.99132 8.20926
+7.19338 8.08381
+7.29139 7.96441
+4.25818 4.4208
+0.802894 0.81938
+0.990115 1.04066
+0.443898 0.490936
+3.44459 3.95977
+9.07812 10.3145
+7.86709 8.26338
+-0.230114 0.390748
+7.50905 8.49199
+-0.715424 1.97535
+2.92248 3.12903
+5.44209 6.62431
+0.991914 1.99037
+5.92275 6.7724
+9.10818 9.2797
+4.46434 4.83462
+4.21122 5.48353
+1.8721 3.40764
+7.04713 7.60526
+3.76581 4.76317
+7.00667 7.36475
+6.87244 7.39431
+7.6349 8.46695
+-0.0728922 0.351194
+5.02925 5.6834
+1.45779 2.83702
+0.339175 1.46574
+6.40414 6.9165
+6.30401 6.91007
+5.6392 5.78172
+5.63288 6.44639
+7.45285 8.89031
+4.09741 4.57929
+8.76728 9.06448
+1.62324 1.84552
+5.72509 6.54553
+8.65273 10.3652
+7.3362 7.8953
+8.96224 10.3113
+0.217316 1.7827
+1.28523 2.90127
+8.78746 9.11602
+8.6075 9.9606
+-0.647788 0.779976
+4.9702 5.47602
+4.15553 4.57497
+1.08174 2.80993
+4.01011 4.8145
+6.79603 7.2317
+4.3711 4.43566
+9.65087 9.79922
+8.19407 9.21784
+3.04008 4.94094
+6.0883 7.23919
+6.88708 6.97172
+0.438073 2.00665
+8.53083 8.83004
+4.22258 4.65233
+6.72856 7.61085
+3.17591 3.18978
+5.07955 5.6938
+2.09043 2.55351
+3.28085 4.43556
+7.29225 8.03925
+7.78034 7.82608
+6.59677 7.67719
+5.56032 6.38139
+8.72663 8.82535
+2.96505 3.11983
+1.67192 2.11727
+7.85386 8.49025
+6.30965 6.72799
+8.53082 9.3801
+2.8976 3.39972
+8.90427 9.44661
+-0.0665785 0.410254
+4.58099 5.81135
+1.88015 2.21838
+3.38693 4.10149
+7.46378 7.68246
+8.80985 9.72212
+6.54877 7.25642
+7.18249 7.71509
+7.41978 8.64805
+1.00839 1.78626
+0.39421 0.526751
+7.13516 7.28317
+7.28011 7.80573
+1.90158 2.49032
+1.66181 4.17994
+8.81106 9.21133
+9.46151 10.5007
+0.52585 0.575082
+7.66495 8.64072
+7.72794 8.50991
+4.92409 6.23879
+2.28769 3.21774
+3.62671 4.40932
+5.77688 7.31314
+8.94253 10.0664
+0.416618 0.635111
+1.81377 2.41356
+7.91755 8.83363
+1.62715 1.82626
+8.22065 9.51656
+0.020228 0.724724
+8.81119 9.95764
+8.66509 9.61079
+5.28201 5.32152
+3.95724 4.22138
+7.09339 7.77685
+9.63428 10.1514
+3.69117 3.779
+3.82195 4.76757
+5.75824 6.62265
+3.69984 4.75163
+3.58259 4.8788
+8.32635 8.85873
+5.81959 7.32506
+8.11265 9.14304
+2.20118 3.32511
+7.79582 8.52691
+6.5891 7.13584
+0.385393 0.440656
+1.13414 1.9951
+1.76482 2.69977
+4.76194 5.82757
+6.33633 7.5348
+4.7663 5.65083
+1.98298 3.01285
+0.956973 2.38629
+5.60955 7.65827
+9.11064 9.14351
+2.99933 3.37975
+3.36304 4.57437
+3.89886 4.50733
+8.73838 9.3514
+9.11824 9.66042
+1.47961 2.93909
+0.615297 1.13217
+1.70646 2.32478
+4.35168 4.99362
+0.986601 1.18332
+4.01551 4.92342
+7.68944 9.86838
+4.47611 4.85316
+0.051839 0.86288
+3.59624 5.5628
+7.08729 8.90374
+9.53464 9.9196
+4.69871 5.74189
+8.43146 10.6889
+3.23774 3.77777
+9.35399 9.62741
+1.15259 2.69451
+6.6368 7.33773
+5.26395 6.09857
+6.87415 7.21717
+-0.925645 1.06118
+8.49641 8.67659
+2.31486 3.25354
+2.51057 2.58303
+0.921997 1.48762
+6.29777 6.74738
+4.03945 4.27305
+7.1668 7.3471
+8.44572 8.80343
+7.16937 7.84526
+8.89008 9.4332
+7.01815 7.66319
+-0.420804 0.982878
+1.59755 1.64672
+0.700814 0.72579
+6.3138 7.37379
+8.49276 9.93522
+-0.795656 0.819657
+0.772253 1.05926
+0.917593 1.3917
+3.30076 4.12274
+-0.0237176 0.260552
+6.82385 7.49119
+6.98638 7.52012
+8.24915 9.08397
+4.17486 4.25908
+3.08435 4.64404
+8.17114 9.91412
+8.95923 9.3751
+0.596707 1.89462
+0.982917 1.40236
+6.79552 7.36657
+8.2599 9.69551
+8.85126 10.4342
+7.98967 9.14514
+0.766355 1.63286
+7.76211 7.99247
+5.23163 5.89338
+4.4707 5.50457
+9.257 9.27862
+2.11049 2.59654
+1.65501 2.06238
+0.551768 2.10873
+0.0285582 0.194421
+3.66153 3.85615
+5.07097 5.55806
+5.29145 5.80735
+2.03499 3.0863
+0.73171 2.29494
+2.63023 3.6417
+6.17478 6.25997
+5.79646 6.46363
+9.10633 10.5516
+7.23415 7.84823
+6.49951 7.1506
+9.94647 10.0242
+7.91236 8.09097
+7.8127 7.97662
+3.34238 3.42907
+8.50796 9.8311
+8.75792 8.98028
+9.34125 10.4441
+2.84413 3.71602
+1.49884 2.35652
+7.52317 9.18955
+9.5587 10.3525
+4.85436 6.1181
+5.91369 6.12194
+6.88463 8.34471
+1.51952 2.99156
+4.29022 5.12674
+8.0229 8.41246
+2.44841 3.04779
+7.59975 7.91485
+2.74491 3.62575
+0.0169968 0.240919
+5.85351 6.29039
+4.99825 5.93439
+2.153 3.35304
+1.19032 1.41763
+6.13337 7.80615
+7.05013 7.89364
+8.38056 9.92
+6.35525 6.64521
+3.93342 5.15885
+2.87656 3.47116
+3.56176 4.41159
+6.72084 7.9171
+8.03801 9.12442
+1.03329 2.56255
+7.64542 8.61709
+2.85627 2.89437
+8.8303 9.79838
+1.08032 2.34573
+7.51366 8.39169
+9.09685 10.3677
+6.753 7.41904
+-0.217662 1.42059
+6.72492 7.97553
+7.99325 8.8976
+0.765372 1.10894
+4.37958 6.04671
+8.72027 9.58928
+6.00234 7.29277
+8.43912 9.25356
+2.98816 3.17389
+0.4292 0.552167
+1.69827 2.80318
+5.99904 7.09981
+4.68367 5.87791
+-0.203208 1.09587
+2.65367 3.28472
+3.87051 3.88111
+6.36178 7.18853
+-0.0815935 0.200848
+6.82255 7.18488
+4.99295 5.08405
+2.67155 3.08447
+5.82099 6.77145
+8.76434 9.01086
+5.94982 6.18665
+3.23369 3.71743
+0.934129 2.73456
+1.13233 1.24208
+8.21931 9.03906
+6.25425 6.69972
+0.971299 4.21205
+5.68426 6.45281
+2.85786 3.3955
+8.17715 8.88439
+2.72802 5.01235
+6.12811 6.53711
+5.22878 6.45864
+0.453655 0.922032
+0.466162 0.85262
+2.40916 2.64759
+5.63583 6.37476
+2.18434 3.14105
+0.912811 2.08432
+8.9464 10.1515
+6.77323 7.27133
+0.7167 1.60579
+5.89813 6.32997
+7.66593 8.4611
+6.54145 6.88337
+5.95421 6.21188
+1.10383 1.92226
+5.37168 5.65707
+1.51874 1.66339
+4.60748 5.00384
+8.97354 10.5394
+2.05022 3.20373
+8.17316 8.19283
+2.33792 2.72643
+8.81577 9.3704
+5.95738 6.59855
+5.69025 6.17335
+6.91889 7.88142
+2.17529 2.81528
+6.65046 7.19698
+7.10694 8.78046
+2.09613 2.47484
+1.92423 2.25333
+-0.0906039 0.861376
+6.61481 7.70609
+6.7448 6.84276
+3.43655 5.28405
+6.05404 6.48902
+3.24637 3.36149
+5.69528 5.77157
+5.12352 5.31024
+7.65858 8.80828
+3.69209 4.4851
+0.25765 1.29637
+3.1537 4.13191
+3.12328 3.83765
+2.99798 4.8748
+4.49566 4.67827
+3.50822 4.03987
+8.00334 8.34084
+8.61039 9.00704
+0.0332147 0.166124
+4.55193 5.36546
+4.20308 4.31589
+0.955466 1.20095
+-0.382972 1.47625
+0.803913 1.01916
+3.78333 4.0707
+6.58604 6.70173
+3.02066 3.82562
+1.16515 2.2816
+7.87242 8.24214
+4.057 4.60368
+2.84714 3.59726
+2.77804 3.69136
+-0.139996 1.36416
+4.50647 6.37579
+8.86647 10.1549
+9.24372 10.1442
+0.743107 1.84722
+6.18761 7.65841
+0.214887 0.443938
+8.8513 9.55063
+4.04856 5.79916
+6.69671 7.10025
+6.97477 7.79702
+4.82551 5.10538
+0.821772 2.85828
+9.3086 9.74805
+5.45623 6.66668
+7.64296 8.67451
+7.53052 8.31024
+7.45352 7.5063
+1.31412 1.4979
+7.81176 8.48083
+0.228964 1.73207
+5.52579 5.93103
+6.58544 8.48938
+2.75407 4.18746
+3.21396 3.96298
+1.13806 2.34106
+0.899331 2.87945
+5.69016 6.61624
+2.48172 2.58082
+0.676004 1.43405
+3.41766 3.9503
+0.104554 0.298373
+6.50673 8.21831
+6.00349 6.69385
+9.62453 10.3147
+4.09379 6.02911
+-1.12803 1.68823
+1.83324 3.43133
+8.30576 9.09288
+-0.363911 0.405218
+1.91686 3.34928
+6.98331 7.15885
+-0.31591 0.996789
+0.145813 0.35408
+5.32016 6.13679
+6.99664 7.48644
+-0.140875 0.821045
+9.0119 9.19742
+1.69616 1.72453
+4.38064 5.07542
+6.85898 7.55478
+3.9145 4.27935
+5.77592 6.16806
+1.45345 3.01301
+4.13024 5.59662
+8.14557 8.41669
+4.00075 4.829
+-0.283024 1.59436
+5.92468 7.17507
+6.84458 7.18356
+1.06987 1.42839
+8.618 8.66235
+0.432802 1.59512
+3.78058 4.36051
+1.6113 4.21135
+6.73475 7.01057
+6.74819 6.90498
+6.93146 8.54681
+9.02605 9.91613
+3.888 4.00526
+1.07958 2.27915
+4.78456 5.10764
+3.92952 4.89555
+9.09348 9.30304
+6.73107 7.21036
+7.42366 7.73225
+4.04079 4.72919
+1.21726 1.34683
+8.82903 9.73504
+0.577663 1.00786
+1.56822 2.08675
+4.84315 5.44994
+1.01008 1.16524
+5.99782 6.01535
+0.996739 1.75305
+4.76128 6.39012
+8.93563 9.51972
+-0.0698166 0.453543
+5.9084 6.95139
+0.535401 0.692258
+4.80729 5.48335
+3.42581 4.76147
+3.58715 4.43541
+7.50236 7.71227
+5.19742 5.87901
+1.79752 2.43097
+7.29762 7.57608
+5.65169 6.47762
+6.02249 7.93642
+0.840131 2.81176
+6.2646 6.96911
+7.46014 8.17136
+9.79049 9.94054
+4.61094 5.35819
+7.30902 7.41873
+1.21883 1.84621
+6.41743 6.57736
+1.53114 1.62859
+6.73237 7.47083
+6.05618 7.56831
+7.63374 8.16821
+5.20839 6.05382
+0.619043 1.44065
+2.38657 4.88786
+3.88289 5.18788
+4.42283 4.51106
+9.15575 9.22388
+3.18678 3.72243
+3.20638 3.65935
+4.2219 4.97961
+4.63725 6.90959
+2.57123 2.59101
+4.08581 4.37325
+6.53926 6.80412
+1.77475 3.89149
+9.22854 10.426
+2.67375 4.36551
+3.17194 4.0433
+1.10304 2.0348
+3.67233 4.04957
+3.23526 3.5012
+5.17684 6.47301
+4.4 4.67662
+4.15842 5.85903
+5.88496 6.61616
+7.26489 7.51279
+4.17402 6.6997
+-0.540216 0.54573
+4.36063 4.60442
+9.18146 9.96239
+0.977216 2.42032
+9.09143 9.61178
+5.06686 6.23076
+2.04772 2.92048
+1.4154 2.00707
+7.80442 9.54824
+4.55549 4.7148
+7.56964 8.80172
+1.35347 3.21648
+9.12751 10.0605
+1.81735 2.06061
+5.63798 8.0918
+6.79492 7.98002
+9.23053 10.1299
+1.74639 2.02724
+3.71825 4.09879
+2.4995 3.42493
+4.1255 5.66758
+4.75493 6.99687
+8.22481 8.72036
+6.13689 7.53026
+5.41315 5.66358
+4.21425 5.62743
+6.22936 6.44392
+2.02303 2.96414
+-0.0655462 0.130508
+6.1487 6.70994
+4.36674 6.24985
+7.51129 7.63176
+7.9729 8.98613
+3.92117 4.15596
+4.54398 5.43399
+6.34248 6.92305
+-0.550253 1.16167
+9.15142 9.53717
+8.99354 9.65952
+6.28988 7.90053
+3.36505 3.782
+8.80005 9.70553
+1.99947 2.18573
+1.15023 2.07069
+0.253723 1.32958
+2.0392 2.93977
+2.89024 3.00836
+8.16735 8.2049
+1.49508 2.95258
+6.19092 7.44552
+2.33328 3.06758
+6.44166 7.4649
+7.34749 7.79488
+7.5557 8.04141
+2.76812 5.13617
+7.97308 9.25668
+4.73539 5.22234
+7.53377 8.41651
+-0.355405 1.36499
+4.72111 4.73744
+-1.22753 1.84842
+5.5033 5.63808
+3.95421 4.19313
+6.24752 6.98229
+4.49694 5.07277
+3.70871 4.30093
+1.31984 1.50116
+7.16044 8.70868
+2.44587 3.34659
+6.08322 7.20376
+2.75012 2.82555
+0.0394442 0.863634
+3.90896 4.73696
+4.77494 5.04158
+8.41473 8.82932
+1.7049 2.71024
+9.01684 10.1044
+4.57959 5.01066
+3.2484 4.21875
+1.11596 2.88792
+3.53616 4.14001
+5.80672 5.82478
+5.85844 7.70293
+6.18239 6.30124
+2.22913 3.23412
+2.97521 3.08481
+2.2749 3.70611
+2.3457 3.86609
+2.71695 4.04473
+7.22863 7.40115
+1.80428 2.39815
+1.80781 2.33028
+2.78662 3.14936
+9.40717 9.94906
+6.54968 6.80773
+2.76862 3.24492
+1.96034 2.87404
+3.53295 3.54927
+5.36042 5.67073
+8.63339 8.93752
+0.932415 1.70402
+4.32923 4.55594
+9.3491 10.4969
+0.121416 1.15499
+-0.172998 1.36319
+2.02349 2.29887
+1.75352 2.35329
+0.502555 2.01665
+6.71754 6.80014
+3.35175 3.93337
+7.17133 7.9851
+8.51299 9.95771
+5.86103 6.36734
+1.44593 3.46008
+4.49699 4.60855
+2.29261 3.10053
+6.68713 8.19499
+5.43776 6.84387
+8.58591 9.02134
+5.24746 6.15595
+1.3847 2.5074
+6.62143 7.07775
+1.7101 2.077
+9.70898 10.2789
+6.67451 7.92058
+2.56858 3.60374
+1.61917 2.60482
+1.77902 2.16908
+4.76209 6.00461
+3.8894 3.98269
+7.0278 7.276
+5.4866 5.59417
+1.69306 2.92506
+2.45744 3.76592
+2.5689 2.80611
+5.98283 6.06154
+9.5267 9.9626
+9.55652 10.4128
+6.6111 6.64606
+3.38826 4.26111
+3.61887 3.73455
+4.14924 6.13796
+7.15863 7.28212
+5.78984 6.56662
+2.09304 2.2681
+4.39867 4.88557
+6.20907 6.81034
+4.63336 4.91476
+0.939805 2.43621
+1.56774 5.13599
+8.40908 9.82058
+2.06273 2.20306
+2.53524 5.01482
+2.9314 3.23661
+2.48535 3.47368
+0.366389 1.4699
+8.81131 9.01654
+2.05102 2.87972
+1.9699 2.22723
+6.18333 6.98224
+1.3425 2.4443
+0.767883 1.77423
+3.1538 3.43248
+0.891006 0.903458
+5.7136 5.8713
+0.437569 1.37539
+3.98533 5.01646
+8.65764 9.89518
+3.74889 3.98561
+7.74507 8.30657
+8.24671 8.43006
+6.88467 7.42036
+1.99426 2.03522
+1.90486 2.04181
+1.12911 1.71807
+9.25253 10.105
+1.92989 2.0346
+5.60044 6.25585
+9.16848 10.087
+6.67824 6.72257
+1.88522 2.80222
+0.242758 0.852689
+5.09249 7.71484
+5.54974 6.44414
+7.66767 8.72936
+3.48884 3.83156
+3.4697 5.14646
+8.48582 8.7692
+6.76259 7.06897
+7.83856 8.62005
+5.81853 6.76571
+2.04803 2.94439
+6.85396 7.22985
+6.52449 7.39764
+9.26838 9.34809
+4.64449 5.64975
+7.51845 7.80279
+-1.27268 1.65344
+0.686101 4.20373
+7.80552 8.37119
+7.20419 8.35284
+9.33962 9.87975
+4.31238 5.58683
+2.39198 3.84398
+1.29248 2.59269
+4.71612 6.195
+5.27332 6.52174
+7.71492 7.84702
+8.18064 8.72233
+1.55223 2.31294
+6.34374 7.31758
+6.48966 6.92611
+2.62268 3.09895
+4.09064 5.06197
+2.66367 4.12126
+1.53391 2.93092
+8.64516 8.70655
+9.20047 9.28957
+4.00474 4.11716
+8.5418 9.45901
+8.73386 9.73253
+9.22596 9.63179
+1.34204 2.7834
+8.4489 9.21027
+7.75158 8.51085
+5.98856 6.11212
+1.29906 2.08111
+9.24315 9.76291
+6.84345 6.91607
+5.88294 5.90545
+3.03022 3.39941
+3.22222 3.4089
+1.12791 1.65898
+6.70232 7.36336
+8.60042 8.82377
+1.26451 1.30362
+2.76682 2.92693
+1.54763 2.19582
+6.5865 7.24173
+4.15242 4.21742
+8.39615 8.78524
+1.67017 2.08717
+9.03012 9.97041
+2.31463 2.45877
+8.29872 8.51813
+1.66689 2.51919
+-0.807606 1.47794
+1.31452 1.94418
+0.0739222 0.512106
+4.23577 4.25889
+7.45273 7.97505
+3.34234 3.46608
+7.97304 9.14131
+1.9029 2.99946
+8.84087 9.79689
+4.92769 5.68685
+2.74004 3.04513
+0.889257 2.20448
+3.10574 3.9758
+3.91547 4.32303
+7.17475 8.07377
+5.92903 8.03738
+1.57974 1.65527
+3.76339 4.2285
+2.28263 2.7559
+9.53105 9.87477
+2.10154 3.2222
+4.23683 5.34347
+1.38769 2.48482
+5.39838 5.51872
+8.50975 10.1382
+8.04108 9.21474
+8.5252 9.67823
+8.893 10.7726
+7.1294 8.18211
+1.15642 1.73882
+0.436911 0.756698
+3.66142 3.71659
+6.37686 6.7
+8.88506 8.99896
+2.31891 3.79061
+2.61615 2.81909
+1.35216 1.39571
+3.04217 3.52564
+7.8409 9.34099
+0.470596 1.49157
+6.94014 7.18365
+8.05483 8.49979
+8.18511 8.25608
+7.03597 8.45251
+2.47411 2.65172
+0.112716 0.193057
+4.45039 5.10584
+4.53906 5.80013
+5.11702 5.27151
+1.24211 1.90757
+4.64114 4.72912
+1.77254 3.45037
+-0.1275 0.99675
+5.69637 7.67722
+2.21252 2.44032
+3.89623 4.40192
+2.79904 3.15569
+8.37911 9.42424
+5.27199 6.2026
+1.84791 3.75411
+0.522801 0.54806
+3.83644 4.64785
+6.65497 7.55638
+6.75104 6.98564
+2.34979 2.98049
+8.27176 8.60459
+5.07773 5.44064
+1.16934 1.98872
+4.2914 5.37557
+6.83462 7.95408
+3.91405 5.73229
+7.77473 8.53538
+9.23441 9.90185
+4.03659 5.2473
+5.99336 7.8004
+4.2432 5.89276
+6.39847 7.81276
+9.13909 10.4164
+1.12009 2.5649
+2.35157 3.18468
+4.46918 5.55572
+3.82512 5.53666
+7.18238 8.10193
+8.40911 9.23639
+8.99555 10.4192
+6.69547 8.87825
+4.79012 5.34858
+9.23615 10.0986
+-0.590587 1.14603
+2.74289 3.48244
+-0.248403 1.1591
+3.35663 3.7229
+7.37504 7.6481
+6.64796 7.64695
+0.778081 2.41212
+4.49242 4.7772
+8.01419 8.109
+6.6494 7.76619
+8.86331 10.1205
+0.817273 0.937855
+8.00019 8.21556
+6.19405 6.54794
+6.11798 7.30421
+3.40164 4.28921
+5.31927 6.21584
+2.79377 3.40938
+3.59494 3.90321
+7.79218 10.3132
+2.99546 3.86111
+1.71916 3.40283
+6.1768 6.81915
+7.59629 8.68568
+1.59724 2.348
+6.20151 6.5391
+6.30798 6.70478
+0.489786 1.51322
+1.28396 1.86775
+5.18031 5.43007
+6.61276 7.70565
+1.4909 2.11165
+4.56163 5.49277
+1.93598 4.35147
+3.65568 5.00224
+1.68028 2.00363
+7.82874 8.67399
+1.23053 2.87598
+-0.164275 0.194491
+2.58349 4.01302
+1.23279 2.02984
+0.599702 1.09257
+9.50965 9.80164
+2.33108 3.58037
+4.38659 4.62378
+2.65097 2.87349
+0.0537058 0.576502
+4.20415 5.15693
+5.41458 5.98382
+4.37747 5.10347
+2.62536 2.70073
+6.96845 8.15356
+6.91533 8.41638
+9.36431 9.58863
+6.13019 7.25915
+2.7818 3.4951
+9.44641 10.1301
+2.68817 4.19772
+5.65664 5.6814
+8.25308 10.498
+3.50374 3.64458
+1.47063 1.78567
+8.21901 8.98152
+3.99261 4.47339
+2.51395 3.38788
+4.66178 5.24959
+9.08415 10.3467
+5.92351 7.20447
+1.74145 2.35957
+7.62653 8.96797
+6.43542 7.68775
+5.49047 6.56355
+4.9225 6.22555
+0.257967 0.704837
+3.42488 3.52873
+8.67606 9.77824
+5.12981 6.37856
+5.97359 6.32151
+1.58517 2.28129
+0.530687 1.54545
+7.04056 8.15296
+1.8541 3.1902
+9.46286 10.0098
+3.17967 4.02237
+3.49966 3.80271
+6.24894 6.49618
+1.19944 1.59215
+5.30422 6.94823
+7.49137 7.78584
+7.02669 8.16282
+2.21673 3.36471
+7.66183 8.34763
+4.13876 4.87421
+3.0199 4.07124
+8.40439 8.82943
+-0.274649 0.429602
+6.11215 7.65609
+3.34781 5.03006
+1.28231 1.77258
+7.57256 8.59456
+5.36208 5.81735
+7.18511 8.96618
+8.86053 9.49567
+5.39097 5.93211
+6.59094 7.26553
+3.69159 4.01914
+8.73797 8.81611
+1.41144 1.82827
+7.83555 8.07567
+6.13821 8.44907
+5.83432 6.48744
+2.93596 4.66271
+7.03215 7.59658
+1.65252 2.45337
+2.91358 4.90129
+8.94415 9.14642
+5.21005 6.1166
+0.33225 1.17039
+7.40089 8.07586
+9.30427 9.40776
+2.34188 2.81124
+1.02811 3.3344
+6.28117 7.62089
+4.80105 7.10049
+8.90252 10.0057
+2.20932 2.33093
+8.20746 10.6268
+4.31887 5.23945
+9.258 9.8985
+3.80742 4.15057
+1.11313 1.23711
+9.53067 9.70165
+7.95467 8.67187
+9.66031 9.83223
+3.61385 4.09571
+0.623148 0.652817
+7.77809 8.62118
+0.86157 1.98606
+3.12528 3.75815
+1.9363 3.22621
+8.23521 8.99175
+8.95406 10.4487
+3.38526 3.90652
+0.34281 2.0226
+0.739384 0.793829
+3.55637 3.96384
+6.1562 7.28647
+5.30211 7.51385
+1.46275 1.78688
+-0.0144662 0.868488
+0.0740443 0.119828
+9.26206 9.83923
+0.743397 1.40754
+4.68823 6.62985
+8.8291 9.17373
+4.66711 5.09313
+4.023 4.44994
+5.68937 5.79194
+8.04835 8.06763
+6.94662 8.00075
+0.774686 1.13428
+0.381819 2.34757
+2.1235 2.63524
+5.42795 6.89998
+6.07662 6.29083
+6.47821 6.7872
+2.58305 2.6192
+-0.598336 1.23458
+4.29089 5.43332
+8.09914 8.28229
+5.05925 5.35258
+0.181705 0.444466
+3.27849 4.79932
+0.310314 1.43125
+1.13836 2.76825
+1.2529 4.09336
+0.198106 0.608625
+1.77442 2.23777
+6.29823 6.64574
+1.22125 1.37929
+1.77592 3.04011
+1.43999 2.90926
+4.20495 5.32396
+4.98874 5.33211
+8.36483 8.67875
+5.65373 7.14132
+2.8303 3.05037
+3.41509 3.54032
+7.21702 7.85857
+5.79848 5.8913
+4.52711 5.65511
+2.04663 2.66919
+5.76363 6.77903
+-0.153046 0.77878
+4.37474 4.49936
+6.86786 7.81999
+8.92084 9.16368
+7.5975 8.56954
+0.197493 1.07503
+3.99803 4.67019
+9.35123 9.60094
+1.46442 2.4256
+5.21501 5.79612
+8.80879 8.99085
+-0.109252 1.30631
+7.34965 7.87947
+7.08703 8.12723
+0.985946 2.14663
+0.48521 0.856118
+6.57719 6.70623
+8.71165 8.72286
+3.16883 4.8714
+-0.21189 0.412944
+3.6526 4.37121
+0.364649 1.3363
+9.27722 9.35135
+3.47517 3.8793
+5.67149 6.28631
+6.52789 6.61039
+9.36323 10.4189
+4.30743 6.18638
+7.93653 9.4877
+8.24024 8.41475
+2.75692 3.13935
+8.80223 9.1489
+3.42656 3.90557
+8.96598 9.3217
+1.99582 4.84803
+5.1178 5.8688
+4.47901 5.73433
+7.30397 7.85527
+0.18463 0.656832
+7.80806 8.41666
+8.50023 9.42628
+7.67563 8.64756
+9.46783 9.52169
+2.06797 3.3107
+5.08863 5.10167
+0.82146 1.39055
+7.5428 8.04736
+9.09407 10.8208
+9.15219 9.99706
+1.61637 3.46354
+5.3812 5.96247
+9.34115 9.73575
+6.49221 7.30031
+1.56337 3.39704
+8.463 8.60841
+-0.322779 0.658242
+8.50173 8.72125
+0.854851 1.83405
+7.81945 8.12841
+2.60724 3.19985
+5.03714 5.55331
+1.85041 3.36816
+7.26119 7.64364
+5.75223 5.99653
+4.00026 4.43863
+5.00939 6.03009
+6.22879 6.6638
+6.44231 7.18622
+1.66002 1.88587
+2.59781 2.84919
+4.96399 5.40545
+5.70327 6.95018
+6.97141 7.08346
+3.98535 4.6179
+5.96795 7.14997
+5.07581 5.8262
+4.65665 4.98851
+8.65646 8.70986
+3.04175 3.19155
+0.796073 1.0952
+8.24859 8.57828
+5.26952 6.34245
+7.94685 8.78542
+0.193963 0.968524
+6.61159 6.80186
+9.37533 9.79195
+8.94048 9.74959
+5.77272 6.48616
+6.0092 7.86718
+2.52621 2.58938
+8.91347 9.22421
+4.20466 5.45909
+4.82157 5.09167
+7.35464 7.36611
+5.12413 6.45063
+2.12404 2.81187
+8.88875 9.20752
+2.59731 3.20587
+1.54772 2.08968
+6.70449 7.08952
+-0.0967146 0.888521
+3.10207 4.34815
+1.20807 2.35497
+6.00753 6.08492
+3.21837 4.00446
+4.34095 6.0963
+4.24821 4.79576
+4.49523 6.6669
+1.49483 2.52552
+0.0411497 0.641526
+8.3854 9.20954
+8.12419 8.93702
+0.0201515 1.06914
+1.57617 3.44176
+1.4173 1.76847
+5.42261 6.51539
+6.6744 8.46109
+3.05234 3.59179
+6.49059 7.24618
+7.01989 7.69901
+2.34664 2.90601
+9.17324 9.86754
+5.50919 5.70258
+2.40486 4.6009
+3.74368 4.00093
+6.9211 7.33554
+7.41358 8.7413
+8.78284 9.62033
+2.96753 3.01602
+-0.200693 0.535532
+6.4383 6.45049
+8.28835 9.42148
+4.2379 5.35128
+4.68397 5.04593
+5.7185 7.03177
+5.37494 6.43977
+2.99518 4.08138
+7.28064 7.54638
+9.10622 10.4907
+1.23839 1.50915
+6.7823 9.24533
+8.45679 8.62427
+0.106718 0.69304
+2.84119 3.50375
+3.60466 4.51338
+8.04709 8.19023
+3.31632 3.48054
+5.9027 7.46331
+-0.621072 1.13003
+8.57167 8.69262
+0.301047 1.42246
+1.24229 2.44616
+0.962706 1.55754
+8.77327 9.55275
+1.77899 2.44335
+0.368575 1.84726
+9.05918 9.07832
+6.61723 7.68015
+8.59899 8.80383
+-0.133927 0.20271
+5.69266 5.74809
+0.68202 1.52342
+7.17359 7.91482
+5.74049 7.34297
+7.88371 7.9683
+1.58749 2.26543
+3.96728 4.45988
+5.4354 6.88336
+1.68706 1.6976
+6.56907 7.40696
+0.518151 0.724124
+8.99155 9.36995
+6.00506 7.91529
+5.26967 6.11536
+2.37416 2.50887
+8.47983 9.31509
+2.38155 2.54346
+8.08415 9.65214
+1.00693 3.19203
+1.6523 1.73553
+6.85283 6.9958
+4.11425 4.90193
+1.39597 1.58725
+5.05551 5.19458
+5.89969 6.11394
+5.9148 7.26824
+9.32271 9.93989
+1.62911 2.58215
+5.43399 6.14203
+3.11393 3.58792
+8.57619 9.3788
+2.23349 2.7884
+8.09022 8.54326
+9.7114 9.87076
+5.91086 6.10885
+7.35805 7.57276
+0.650002 0.879866
+3.24977 3.75531
+2.73948 3.41051
+3.08006 4.62772
+3.71868 4.31519
+4.13905 5.78577
+1.77297 3.02983
+5.85931 5.89333
+3.68972 3.93193
+1.43922 2.98425
+6.51534 8.33386
+6.6821 7.50874
+1.2541 2.11722
+5.40634 5.54411
+4.55502 4.60346
+4.32484 4.68497
+3.40711 4.31975
+9.20893 10.0853
+6.12594 6.9009
+0.12664 0.347193
+7.53378 8.82258
+7.79572 8.91645
+2.50098 3.39701
+4.17873 4.97732
+1.05822 2.47032
+3.1012 4.97736
+8.42126 8.74568
+7.83301 8.17843
+9.26618 10.584
+3.02667 3.7128
+8.30654 8.69242
+2.87173 3.43275
+6.59917 7.54843
+7.03447 8.20283
+5.75718 6.40637
+2.62899 4.1855
+-0.520148 0.902194
+5.1538 5.61763
+1.25625 2.33142
+4.16336 4.3384
+3.01296 3.41026
+3.16515 3.26305
+2.40944 3.21897
+6.80742 8.57141
+1.15125 1.54824
+8.72251 9.50878
+3.15703 4.04482
+0.470308 0.726093
+0.199979 0.878243
+7.8908 9.17915
+6.91793 7.16038
+4.64783 5.00217
+2.21237 3.03073
+1.5825 1.63362
+3.18806 5.20795
+5.92725 5.95595
+4.65027 5.09868
+6.42204 6.87201
+8.08637 9.40221
+4.95542 6.16185
+7.45987 7.57979
+8.826 9.13961
+4.42078 5.27977
+7.26216 8.97585
+2.26919 3.33512
+9.4077 9.81908
+0.722223 1.03378
+-0.0497795 1.19355
+8.22686 9.31082
+0.0733766 0.93037
+7.47883 7.9062
+5.28731 5.74181
+1.78496 3.61348
+0.690987 0.764344
+2.56442 3.54999
+4.27944 5.43124
+4.04412 5.35376
+0.663756 1.88268
+1.73567 1.78553
+8.07666 9.41842
+7.70138 8.42873
+9.27113 9.55873
+0.982413 2.5565
+0.994807 1.02007
+5.01226 5.31923
+8.87435 10.0597
+1.74836 3.22578
+0.151528 0.191719
+5.82608 6.06438
+1.17239 1.59955
+3.18515 4.11049
+1.92258 3.70604
+1.63692 1.8266
+1.83542 2.66228
+2.21954 3.11425
+3.97546 4.3928
+0.731374 2.05705
+5.44809 5.96359
+9.85934 10.0553
+8.42169 9.63654
+6.68148 8.43446
+2.00014 3.3485
+0.735924 1.73
+1.61833 3.05643
+7.87934 8.67316
+8.67441 10.0032
+0.794573 1.2493
+6.11926 6.41441
+5.2715 5.82597
+9.41854 9.46625
+3.46299 4.06742
+5.6487 5.79053
+1.46503 3.43496
+0.9957 1.53939
+2.4714 3.1301
+0.887049 1.6196
+3.04884 3.19662
+1.24337 2.05758
+7.61142 8.55766
+0.998279 1.64425
+4.74917 5.85236
+2.97632 3.94611
+4.11786 5.62709
+7.40498 7.62083
+1.47854 3.64736
+2.1176 2.64511
+4.55533 5.89436
+7.44618 9.79926
+-0.410242 0.737348
+5.719 6.30861
+8.33692 8.38222
+8.78122 9.98195
+3.75452 4.26866
+2.23771 2.44985
+6.72455 7.61362
+5.9797 6.58846
+6.72885 7.60315
+-0.710302 1.18332
+7.73287 9.383
+6.61213 7.67394
+4.12945 5.68527
+-0.300887 0.341615
+5.77978 6.41534
+8.34001 9.96874
+1.62323 1.8283
+1.71788 2.23905
+7.43484 8.0418
+3.47322 3.8047
+3.47311 3.51261
+7.82093 8.86377
+2.46973 2.99125
+7.91166 8.55065
+3.39807 3.43599
+8.94792 10.0437
+7.70859 8.32487
+5.86852 7.13103
+7.64996 9.19033
+6.66742 7.8092
+7.88241 8.58675
+9.42939 10.3479
diff --git a/wasserstein/tests/data/test_5000_B b/wasserstein/tests/data/test_5000_B
new file mode 100644
index 0000000..5f6e43c
--- /dev/null
+++ b/wasserstein/tests/data/test_5000_B
@@ -0,0 +1,5000 @@
+1.17434 1.46837
+2.58198 4.16589
+0.234041 0.968658
+1.52703 1.59579
+6.7103 7.44033
+3.19227 4.41539
+5.42556 5.57369
+3.45417 4.86089
+3.82256 4.1092
+7.82551 7.90784
+3.9384 4.71796
+5.60335 5.9054
+7.96663 9.8987
+6.30305 6.64853
+7.33246 10.5316
+0.623312 1.09008
+2.63041 2.64616
+5.36028 6.28956
+4.64202 5.91858
+7.55219 7.96304
+7.73736 9.18221
+1.67114 1.84851
+5.07514 5.12159
+7.03732 7.05228
+7.5006 7.59212
+0.244947 1.55875
+0.0170454 1.10485
+1.95394 3.53669
+5.66015 6.01949
+5.88211 7.64639
+7.46698 9.27085
+6.37429 7.10154
+4.54535 4.81932
+8.21203 9.35896
+4.89933 6.20802
+3.68683 4.17831
+0.477467 0.828394
+6.17871 6.77834
+9.77523 9.92676
+0.854808 2.38709
+7.93326 8.3553
+2.10917 2.27771
+4.07045 4.72793
+8.2016 8.8011
+2.9205 3.95746
+2.89806 4.39725
+5.5654 5.78669
+9.5219 9.98543
+7.08591 7.19588
+8.35359 9.57893
+9.81348 10.0345
+8.5994 9.71835
+5.43903 7.25234
+1.82768 2.92724
+4.44952 6.79754
+5.66747 7.34386
+5.88153 6.39253
+3.34008 4.22032
+2.46068 2.76051
+0.370778 2.61681
+6.02508 6.26809
+4.32654 4.93262
+7.41536 7.99616
+8.84229 9.87911
+3.8551 5.84353
+1.56832 2.34694
+6.96099 7.42028
+8.15753 8.72014
+9.23141 10.3815
+7.4484 7.80228
+0.473671 0.874895
+3.15689 3.50687
+3.58122 4.09945
+3.55022 3.74767
+4.42708 5.80211
+4.40956 4.68699
+3.80576 4.61856
+7.29965 8.28614
+7.40582 8.15308
+1.69789 1.77669
+1.66419 3.44308
+0.473997 0.872506
+7.83959 8.52898
+6.22416 6.36949
+-0.187159 0.871822
+0.232336 0.585965
+9.29905 9.44357
+1.4459 2.40589
+2.83008 3.19758
+1.15291 2.12112
+2.58686 3.33896
+6.79362 7.88068
+0.228178 1.48318
+5.60001 6.20258
+4.97803 7.10992
+1.70429 1.962
+2.72659 3.13886
+9.22714 9.25889
+3.84694 3.88778
+-0.282077 1.48155
+9.28756 9.58517
+4.34069 5.59751
+8.63909 8.76839
+8.86236 10.7642
+6.77597 8.41888
+7.30621 8.64164
+0.685607 1.22755
+2.91514 3.22638
+2.72098 3.66837
+8.17528 8.32638
+5.19632 5.7506
+7.34177 8.70639
+5.74082 6.35524
+5.95975 6.69284
+9.40187 10.4488
+2.92761 3.36735
+0.399531 3.13082
+4.83399 4.92635
+7.74539 8.56852
+1.76322 3.5086
+6.54479 6.72963
+7.64362 8.12404
+1.35542 1.45313
+0.214385 0.718085
+1.7006 3.21962
+5.91009 6.47862
+2.21093 2.34636
+5.96919 6.79365
+6.59951 8.22203
+1.54571 1.59397
+3.27012 3.79128
+0.32455 0.622995
+1.73926 2.78017
+9.81035 9.84077
+7.38441 7.85171
+8.90372 9.34186
+7.26323 8.41174
+5.7363 5.97348
+8.25473 10.1281
+2.3981 2.52096
+8.53783 9.63442
+8.51755 9.2735
+6.48614 6.773
+3.40182 3.65137
+2.1353 3.04852
+2.95397 3.73285
+6.98063 7.4963
+4.50189 5.26384
+0.21416 1.49363
+0.632196 1.36307
+6.57833 6.60481
+8.0634 9.33903
+2.79759 2.94462
+4.43747 4.58861
+6.48733 6.86569
+2.28008 3.47037
+6.87452 7.77431
+-0.156821 2.71557
+0.72595 1.78862
+1.97586 2.38196
+8.61839 9.1468
+4.55496 5.68986
+0.26923 1.15728
+9.63757 9.7236
+1.39497 1.96698
+4.8643 5.04172
+6.64675 7.66435
+2.56256 2.6015
+-0.381989 0.611211
+0.676336 1.26896
+8.95304 9.03243
+5.62058 6.07997
+3.36522 4.04276
+8.64868 10.5024
+4.75813 5.19834
+1.96608 2.05864
+9.01449 9.10397
+3.72786 4.51921
+5.6938 6.96584
+1.73499 2.9314
+2.73099 3.41409
+8.77171 9.07665
+4.63865 4.67649
+8.6698 9.30782
+-0.168259 2.09581
+9.29672 9.56
+0.372544 2.60567
+0.450487 1.32919
+6.95341 7.6399
+3.4403 5.24993
+5.53469 6.97831
+-0.79664 1.21306
+5.68831 6.14413
+8.85601 8.95444
+3.83309 5.211
+5.51573 6.5114
+3.64009 3.99648
+4.40759 4.99283
+1.85198 2.6457
+2.72645 3.74803
+2.04751 3.00998
+3.19365 3.9383
+8.09529 9.45596
+8.88173 9.5618
+0.609816 2.67806
+1.57288 2.60884
+1.68354 1.80124
+4.92058 5.9959
+1.48728 1.84885
+0.299669 0.413905
+9.02156 9.56731
+7.50854 8.49023
+0.667131 1.89987
+2.22472 2.58793
+5.84395 8.79426
+2.35839 2.66935
+3.43111 3.69982
+6.71023 7.36801
+6.75697 9.0991
+2.35352 2.85316
+6.73054 7.39006
+9.48673 10.1493
+6.71226 6.72805
+9.22083 9.71889
+8.36513 9.33921
+0.0652672 0.319993
+3.26467 4.60881
+7.62269 7.79878
+6.48608 6.69515
+6.21737 6.88645
+6.56094 6.9699
+1.61317 2.7167
+5.08621 6.29754
+2.24676 2.8076
+3.09943 3.93921
+9.74093 10.0968
+0.417699 1.6381
+9.2958 10.2973
+3.6663 4.1369
+0.0229943 0.448065
+9.2928 10.1833
+3.66334 4.22032
+0.812172 2.19952
+7.88025 8.71192
+8.69379 9.34922
+1.70691 2.95352
+8.28737 8.29985
+5.22491 5.354
+4.03526 4.14084
+6.49359 7.05924
+0.24853 1.44718
+7.86936 8.75135
+5.76 6.68919
+5.85437 6.14314
+5.86292 6.0516
+2.35692 2.91295
+0.0990674 1.29386
+2.9911 3.56188
+0.552671 0.638929
+5.80756 6.22761
+1.21067 1.77175
+4.51882 4.72936
+1.99969 2.89732
+3.65968 6.61987
+0.478582 1.33355
+0.259061 0.289813
+3.89264 5.02474
+0.349236 0.438003
+7.70442 8.1729
+7.90389 10.1876
+3.06898 3.15219
+4.77811 5.29095
+9.76561 9.89451
+4.14295 4.2489
+0.540224 2.28623
+9.60749 10.2284
+8.49555 9.00307
+7.89668 9.76886
+4.12631 4.70897
+7.87898 7.91814
+9.29858 9.52908
+9.24009 9.91544
+3.73498 4.70275
+5.44467 5.9274
+2.13453 4.85697
+2.29607 2.88771
+0.807842 1.82319
+0.319005 2.08473
+1.62 1.63649
+2.20431 3.23869
+2.00132 2.77136
+6.64752 6.71706
+8.12249 8.28379
+7.55541 7.7813
+3.51763 3.64484
+9.21075 10.2811
+2.24501 2.54426
+5.64566 6.46452
+6.72307 8.56698
+3.91728 4.60262
+4.02535 4.29548
+3.0499 3.53135
+1.30677 2.32194
+9.36908 9.90669
+3.92387 4.33848
+2.87312 3.08243
+4.49167 5.2749
+5.43143 6.74905
+6.94595 9.16539
+1.9784 2.00429
+9.42478 10.2226
+3.7185 3.96576
+9.37729 9.50574
+5.34283 6.89736
+4.95341 5.84626
+2.91654 4.28413
+8.26544 9.3076
+6.23114 7.20273
+1.02585 2.21446
+1.6718 2.29591
+2.28926 2.73452
+-0.648145 1.105
+1.44194 2.18562
+6.78584 8.37985
+2.00402 2.08248
+1.64076 2.04067
+0.0419044 0.455962
+5.51723 5.72098
+5.42117 6.81165
+5.70331 5.81707
+4.97889 5.60741
+3.38797 4.46846
+7.20995 7.66784
+3.45388 4.23386
+3.11057 4.35995
+3.29476 4.04676
+2.0519 2.94719
+5.37101 5.38271
+5.99383 6.64188
+7.48444 7.6377
+2.15043 3.05399
+1.54093 1.83799
+5.59223 5.87222
+5.8005 6.08042
+6.1208 7.22563
+1.2938 2.17454
+4.92405 5.0402
+6.91336 7.79688
+1.47978 1.99762
+9.00494 10.8315
+5.84805 6.15303
+4.95368 5.49096
+8.21704 8.31192
+0.715222 2.33517
+0.904183 2.54741
+3.42349 3.74906
+0.627978 2.37092
+8.41477 8.72651
+3.55373 5.58652
+4.12685 4.61533
+0.775274 1.41263
+4.78915 5.08639
+6.35791 8.15015
+2.88242 3.63509
+2.78526 3.07834
+0.39129 1.15933
+3.26615 4.74531
+8.78873 9.8888
+7.25612 7.45972
+4.97452 5.30012
+0.757255 1.35518
+1.29516 2.52446
+4.66838 4.96648
+-0.0720209 0.832726
+2.68276 3.21123
+8.44253 10.0311
+3.40809 4.70506
+1.09617 2.35452
+5.19302 6.73599
+1.25316 1.58101
+6.2056 7.10099
+7.7666 8.52777
+0.301239 1.37275
+0.522829 0.731575
+6.73869 6.96826
+2.41703 3.20567
+4.94617 6.22052
+5.41524 7.68272
+6.0408 6.29938
+0.0642067 0.600878
+6.32122 6.63505
+3.25427 4.70611
+5.88704 6.1678
+8.71533 9.08476
+6.25575 6.88392
+1.54462 1.56366
+3.95938 4.03326
+2.54671 3.66798
+8.48603 9.10156
+3.37369 4.65454
+5.25469 5.64636
+7.02624 7.36449
+8.17061 8.44321
+9.23147 10.1149
+1.45589 2.25886
+6.47702 8.25307
+7.69088 7.91753
+0.442832 0.616926
+8.35355 8.83222
+7.65142 9.58906
+4.04877 5.17345
+0.76012 1.8686
+6.54877 7.40058
+7.41774 7.65429
+8.69655 9.3325
+4.8302 6.25306
+1.77203 1.90284
+3.67485 4.94569
+6.60162 6.72031
+3.05924 3.35235
+0.0823162 1.3486
+8.42991 8.86331
+6.81596 6.83527
+-0.0174808 1.6745
+-0.758131 1.08928
+4.14423 5.46342
+9.26253 9.85714
+7.42749 8.58214
+4.88849 5.86936
+8.99339 9.38141
+8.85301 9.18285
+2.64303 3.45658
+7.1133 8.66473
+3.50745 3.8629
+7.81615 7.83244
+2.94991 3.8741
+7.91822 8.8362
+-0.0553088 1.19059
+7.35558 7.77948
+2.11257 2.20563
+8.57533 9.16338
+2.3515 3.13009
+4.13239 5.38696
+2.20763 2.93941
+7.2451 7.3211
+0.834388 1.57413
+4.47024 6.17855
+4.75947 6.80913
+2.99607 3.54732
+8.15998 8.80718
+8.94688 9.27971
+4.46335 4.9522
+5.30725 5.69786
+7.63989 7.86974
+6.69589 7.69565
+5.34018 6.08115
+8.59515 9.62264
+1.80557 3.22507
+8.62429 8.94242
+1.34532 1.95042
+8.60707 8.80741
+8.03275 9.40327
+4.30357 4.39095
+8.97954 10.7076
+2.18143 3.51825
+3.98695 5.62062
+2.48813 2.60622
+5.56957 6.43776
+5.18249 5.55459
+3.45373 3.64101
+-0.00345662 0.570597
+3.61127 4.69761
+9.37858 10.6205
+7.24635 8.19639
+4.70142 4.80735
+3.30055 5.14257
+0.860415 1.31635
+4.72924 5.46893
+7.47391 7.72644
+6.22287 6.57754
+0.181652 1.01366
+2.14494 2.80736
+2.16406 3.19383
+8.52991 9.22722
+8.74411 9.06935
+0.575831 1.02699
+2.47315 3.0331
+4.2872 4.59813
+5.82293 7.03604
+2.08982 2.25319
+7.3626 8.41994
+1.23867 3.10885
+7.397 7.78026
+6.78837 7.32977
+0.829368 1.56617
+9.23075 9.35172
+6.76562 7.23578
+0.42851 0.839401
+4.83626 5.5852
+0.150032 2.45322
+2.16811 2.47439
+5.60245 5.81188
+7.43707 7.46519
+0.167317 1.44642
+4.9732 7.58343
+8.67391 10.2957
+0.318592 0.639284
+3.365 4.25929
+7.83683 8.88895
+5.20557 5.30114
+0.940347 1.74022
+5.39149 7.13464
+1.10826 1.27913
+1.9147 2.31276
+0.935283 2.49181
+3.67898 4.33336
+5.10125 6.07734
+0.348807 0.839242
+0.310986 0.58381
+2.03594 2.43119
+5.49755 5.94215
+1.94885 3.34409
+9.66806 9.97883
+4.79099 5.45155
+4.81158 5.30001
+5.17667 5.90019
+9.64168 9.99177
+1.14899 1.22792
+0.466236 0.952985
+6.93679 7.72282
+2.97285 3.23931
+9.22517 9.24315
+7.25783 7.46414
+4.37304 4.51815
+4.01069 4.02979
+0.843132 1.80443
+4.78572 6.04237
+6.02471 6.38074
+4.99536 7.76852
+4.97442 5.17384
+0.731231 1.49497
+2.2797 2.90845
+9.13211 10.341
+4.19545 5.08597
+6.13127 7.09817
+2.65124 5.02208
+5.40235 7.12912
+6.86258 6.91991
+8.24317 8.55273
+7.6877 7.69875
+3.33922 3.53776
+0.089484 0.40755
+1.34909 1.68726
+8.43113 8.72899
+4.90038 5.55994
+0.308089 0.490555
+5.42628 7.1433
+2.11647 2.56987
+3.56934 4.1619
+8.35794 9.24416
+8.8645 9.69151
+5.10701 6.0036
+7.66385 7.8412
+2.89952 4.55221
+6.01533 6.38269
+-0.945182 1.07304
+1.79537 1.85576
+-0.0313338 0.501067
+8.85689 8.87522
+1.61143 1.7773
+9.53229 9.84943
+3.51669 3.81091
+-0.448016 1.10903
+3.16889 3.439
+4.30534 4.36372
+6.20158 8.09618
+2.20949 5.23616
+3.29459 4.17079
+3.90101 4.05611
+5.89688 6.85702
+0.734474 1.04471
+7.84341 8.02702
+8.69431 10.1086
+9.73194 9.92195
+7.63516 7.70631
+8.51416 9.33072
+-0.0712911 0.361001
+2.76979 3.22708
+5.34404 7.5165
+5.64429 5.79865
+0.0755012 0.363483
+5.05631 7.27153
+-0.60164 1.09659
+0.457228 0.876186
+4.27092 5.38033
+8.63891 9.04134
+6.29608 7.04242
+8.97795 9.93013
+5.00385 5.57737
+8.48068 9.44885
+7.35543 7.78492
+3.55698 4.01035
+-0.268117 0.649128
+0.633184 0.66254
+4.54216 4.81132
+6.15574 6.35276
+4.3663 6.36286
+1.45231 2.07039
+7.37031 7.9157
+5.30961 6.3506
+5.80757 5.81762
+4.91767 4.97519
+3.45667 3.60965
+1.7934 2.3807
+4.33289 5.41047
+1.16021 1.29979
+3.75172 4.53521
+3.10835 3.1275
+2.68167 3.00314
+4.10639 4.24094
+4.90776 5.74069
+7.30861 7.86666
+3.52822 3.70998
+5.22222 5.28033
+0.00866476 0.326377
+7.73247 8.61481
+4.25231 4.77499
+8.41148 8.54604
+2.95389 3.63497
+7.76126 9.69124
+6.41218 6.69682
+4.86285 6.44503
+1.84783 1.9065
+4.08788 4.11706
+9.17473 9.50133
+5.15091 5.78649
+1.27694 3.33579
+2.92648 3.37855
+9.37392 10.5123
+4.81878 6.34991
+8.38702 8.83716
+5.07771 6.33618
+1.47438 1.75588
+6.20935 7.11166
+1.08286 1.38
+1.40048 2.0157
+6.60355 7.26234
+5.28396 5.90003
+8.9525 9.59216
+-0.0305792 0.544664
+-0.571491 0.735471
+6.287 7.03679
+5.35225 5.4104
+0.095812 0.605976
+4.33523 4.4048
+6.13288 6.80949
+4.14654 5.5505
+-0.213214 0.260592
+7.56188 7.83088
+7.8132 8.65963
+8.02469 9.3254
+0.00641711 0.420562
+7.49269 8.15849
+9.26359 9.4366
+5.74008 7.86317
+8.62729 9.78825
+4.28946 6.20553
+3.19174 4.54991
+4.16992 4.25203
+2.46138 4.11583
+1.92971 2.16701
+3.43028 3.80842
+6.98297 7.28388
+7.51884 7.55947
+7.79102 9.44326
+0.416342 1.32311
+9.35398 9.85201
+8.72997 9.10384
+6.23398 6.88888
+7.46984 7.4875
+5.92603 6.66938
+1.77761 2.58697
+0.835966 2.06139
+9.63284 10.3565
+6.13677 6.42768
+0.151375 0.382404
+8.10315 8.13441
+5.52283 6.28113
+1.00873 2.44226
+2.5239 3.89871
+5.40599 6.72653
+3.43407 4.0068
+1.22444 1.26601
+7.04395 7.80599
+3.75987 3.77123
+6.43597 7.06249
+8.34435 8.87418
+8.25853 9.04009
+0.415321 2.32725
+0.639046 1.75525
+7.83226 8.12538
+9.55429 10.2734
+3.658 4.35867
+1.8588 3.93292
+7.38922 8.16823
+8.53626 9.23024
+0.848152 1.13412
+6.31667 7.2348
+3.81584 4.62621
+9.24748 10.7408
+2.75953 2.95288
+5.70188 6.62278
+4.22202 4.45368
+3.24616 3.88779
+1.05053 2.09846
+8.67718 9.52693
+2.14107 2.71959
+1.10518 2.69689
+5.01476 5.54139
+4.69244 5.20358
+8.88285 9.93012
+2.55228 2.77382
+6.72118 7.50057
+7.58999 8.71573
+1.83763 2.13481
+4.86135 5.27995
+4.39794 5.42117
+1.42512 2.98262
+4.80489 5.34701
+2.7993 5.13702
+7.52122 8.41729
+9.08613 9.37543
+1.1555 1.3935
+7.34071 8.0428
+8.33361 8.40349
+2.514 2.54741
+8.25732 8.41758
+1.65337 2.57964
+4.20527 5.06565
+0.723443 1.06987
+5.85836 6.64701
+7.908 8.07591
+5.01839 7.0105
+3.15908 5.10364
+4.3574 6.67192
+2.06662 2.46437
+7.5595 8.9108
+7.94919 9.20231
+4.11889 5.49714
+7.28151 7.51881
+1.30685 2.09479
+3.08479 4.47364
+4.50916 5.91511
+7.31605 7.63868
+3.14469 4.07035
+8.38431 8.87993
+7.42277 7.64967
+4.22472 4.26323
+8.49871 8.90746
+7.44431 8.09014
+8.35213 8.7504
+3.85634 4.37584
+9.12975 9.77042
+-0.326056 1.17374
+3.53802 4.06211
+6.81775 6.8467
+8.19106 8.64489
+4.20526 5.37727
+2.74081 3.72143
+0.49642 1.10775
+7.76606 8.00524
+4.79825 6.38926
+1.99478 3.20484
+4.69853 6.29508
+5.73058 7.18643
+8.11708 8.64257
+9.62375 9.84838
+5.95271 6.38989
+9.0193 9.93848
+3.91188 4.10834
+6.065 6.60546
+2.62354 3.60072
+8.53665 9.06824
+6.40691 7.44693
+1.62959 2.5825
+9.4128 9.87031
+6.24697 6.62684
+3.31136 3.45626
+4.80347 4.9935
+9.21711 9.53416
+-0.491547 1.72886
+4.75174 4.87217
+0.86329 1.53331
+2.4586 4.2578
+5.10301 6.2815
+5.08302 5.86788
+6.12434 6.78948
+9.68323 10.0973
+3.52576 4.40424
+4.9925 6.89084
+0.846638 1.80782
+1.09709 1.7685
+8.38592 9.03312
+9.56243 10.2682
+5.03592 6.6429
+7.8609 8.04599
+1.21404 1.31975
+7.47824 9.2063
+1.47849 2.68795
+1.2909 2.06381
+5.21288 5.54616
+6.27218 6.99345
+4.77622 5.08494
+3.30665 4.14735
+3.38947 3.55545
+7.71197 8.53162
+1.10565 1.50806
+0.7889 0.984689
+2.88598 3.33244
+5.70958 5.81232
+5.16567 6.24511
+6.91255 7.25784
+-0.401084 0.753156
+4.81138 6.20671
+1.67301 3.58501
+7.19478 8.25624
+1.24428 2.2523
+4.31631 5.33357
+0.589196 1.02017
+5.69207 6.97803
+2.3854 3.25501
+4.1362 4.91135
+8.9932 10.3184
+7.95871 8.45158
+4.03213 5.26347
+3.09506 4.06425
+-0.0310321 0.738171
+7.35733 7.61512
+2.48488 2.96253
+4.72098 5.69867
+5.5395 5.96914
+3.17854 4.283
+6.50012 7.33744
+1.93266 3.00941
+1.49319 2.71826
+9.0187 9.13099
+7.15259 7.40691
+8.71939 8.93257
+1.57203 3.11249
+0.933429 2.16903
+2.99663 3.71667
+2.06144 2.81311
+7.9072 8.2103
+0.490069 0.614737
+7.84111 9.70812
+1.15363 1.6421
+1.15475 1.43307
+8.2228 9.92116
+7.76825 8.40724
+6.15122 7.31322
+7.1427 7.49294
+2.30516 2.7019
+2.03336 4.03387
+8.3918 9.85707
+8.57214 9.59345
+3.8057 4.1119
+8.9223 9.38556
+9.32051 9.60504
+7.13349 7.69154
+1.71855 2.00425
+5.10333 6.0605
+-0.149137 0.80973
+0.466224 3.1698
+4.19165 4.29604
+1.64018 2.3161
+9.40397 9.89211
+5.21738 7.06323
+0.525526 1.0331
+8.06992 8.08704
+9.81539 10.0915
+9.33514 9.50521
+5.95494 6.54519
+9.21466 9.35909
+4.96603 5.18164
+3.89238 5.53056
+5.04546 6.32916
+8.63758 8.65805
+7.03226 7.57074
+0.32029 1.10893
+0.194176 0.992252
+8.79061 9.50848
+0.239137 0.300717
+7.7234 8.43747
+3.43679 4.28954
+8.31382 9.18928
+1.39612 1.67253
+6.95733 7.39846
+1.29129 2.12185
+7.93611 10.2305
+3.67764 4.17562
+1.38149 2.42407
+2.2847 2.48412
+9.28655 10.0661
+2.94115 3.21326
+7.04238 7.91536
+5.06012 5.61526
+8.95611 9.91736
+2.18524 3.44007
+1.0692 1.10987
+4.37019 5.18443
+5.82014 6.441
+1.68642 1.70458
+4.93783 4.9535
+9.42003 10.1196
+-0.356795 1.30987
+1.37778 2.80527
+9.54126 10.1758
+8.67413 10.5984
+0.914291 2.0697
+6.08696 7.09832
+2.82202 3.31103
+4.07818 5.50195
+2.85223 3.67449
+6.03006 7.10863
+8.84655 10.528
+5.08031 6.2001
+1.00272 2.74191
+0.169102 0.223253
+0.025089 1.26534
+-0.203339 0.64667
+0.899666 1.48885
+0.74235 1.49976
+6.28212 6.80412
+5.65159 5.93106
+2.1686 2.7445
+5.02936 5.43091
+8.07124 8.80499
+8.65696 8.95802
+7.68394 8.365
+8.65062 8.69146
+0.058248 1.19535
+5.74545 5.84057
+6.05244 6.52152
+9.3878 10.3328
+7.71379 8.88044
+3.32961 4.54105
+8.51987 8.62854
+4.10821 4.16902
+9.47639 9.78723
+4.72417 4.84793
+2.32867 2.94068
+9.52275 9.57815
+5.32867 6.96127
+4.32462 5.1508
+4.46919 6.45961
+8.62661 10.9533
+0.0244049 0.56156
+1.49207 1.73164
+7.03156 7.81168
+5.88587 5.89732
+8.43632 9.65085
+7.52612 8.06726
+4.82464 5.6193
+3.8062 3.90356
+2.42708 2.51646
+2.06458 2.45877
+0.427218 2.24283
+7.42616 8.11513
+0.617708 1.01833
+8.74218 9.03592
+-0.213346 0.599112
+9.05291 9.59124
+5.20365 5.54277
+2.85289 3.99509
+3.08468 4.58456
+0.136826 0.685254
+3.87191 3.99021
+0.970836 1.49673
+2.44355 2.53584
+8.88615 9.94545
+3.90591 4.52798
+1.52518 2.50658
+7.21268 9.07745
+0.767314 1.23833
+8.62975 9.42367
+6.71524 7.67686
+7.61205 8.48292
+5.312 5.65087
+4.75627 5.96261
+7.90674 8.0753
+7.37887 7.71478
+3.74483 5.52984
+2.7187 2.85544
+4.7902 5.62159
+2.89671 5.19815
+7.37268 8.72506
+7.11916 8.28301
+9.19814 9.75279
+1.2085 2.60113
+-0.632009 0.889734
+7.99858 8.39743
+6.48346 7.10822
+6.30616 7.06648
+5.56514 6.51183
+2.41505 3.56224
+6.83749 8.84447
+9.05111 9.46906
+7.77476 8.4091
+6.11378 6.31232
+4.42882 5.69917
+5.88107 8.052
+3.75437 4.08893
+2.70487 2.77664
+7.26028 9.77257
+1.44621 2.73267
+2.0384 2.60397
+2.95402 3.68949
+6.04766 6.4054
+0.716046 1.77698
+1.5084 1.72988
+2.58426 2.80376
+8.05255 8.59793
+6.06336 6.20709
+3.29813 4.31473
+2.53477 4.92554
+8.78711 9.88634
+9.26627 9.82082
+6.70683 6.81257
+8.25978 8.99788
+7.28054 7.64237
+5.14556 5.20711
+4.20431 5.87866
+8.96592 9.97597
+4.06216 4.41519
+8.49174 11.0491
+5.24547 6.03094
+4.65885 5.95835
+5.09606 6.34846
+6.30463 6.65933
+6.48022 9.56168
+1.38088 2.98143
+0.486911 1.16767
+8.16327 9.34821
+0.768885 0.782616
+4.51699 6.08086
+9.55086 9.70242
+2.86802 3.72489
+1.88496 2.18749
+4.31876 4.33726
+8.38871 9.45631
+8.80634 9.36198
+5.232 6.42399
+9.86919 10.0492
+3.61902 4.53086
+3.13118 4.42364
+2.69395 3.1816
+-0.303144 1.32309
+4.28871 4.36739
+3.8631 4.08745
+4.9291 4.98968
+7.14273 7.25505
+2.56623 2.59122
+6.01753 7.72265
+6.76051 7.53954
+6.76933 8.14741
+0.933137 1.83537
+7.9357 8.57904
+5.55847 5.59984
+4.25563 4.3345
+4.28087 5.21348
+8.88534 9.06554
+1.88575 2.94002
+5.26613 6.04562
+0.514249 1.45538
+0.130644 0.501645
+4.30564 4.86337
+1.57246 2.38451
+0.303814 1.77474
+4.22675 5.02783
+6.75381 6.78634
+5.64096 5.9725
+6.76159 6.98142
+2.35569 2.39119
+3.29794 4.95962
+6.55055 7.03366
+5.31474 5.69404
+9.01335 9.16988
+8.58306 9.37831
+7.06522 7.07778
+1.14695 1.74744
+3.15507 3.22865
+5.5925 7.14168
+2.14679 3.68767
+7.54789 9.71878
+1.5667 2.08742
+-0.604726 1.66718
+0.306012 0.54799
+2.61731 5.08257
+0.80957 1.74655
+8.22035 8.81637
+4.401 5.449
+8.89389 9.01988
+4.80574 4.9322
+2.19895 2.88565
+9.06688 10.8095
+1.23727 1.58699
+7.14836 7.92057
+4.65155 6.15149
+0.563061 2.16535
+7.66764 8.0341
+8.32324 8.42774
+4.54541 5.11069
+8.0237 8.09992
+7.26113 8.09404
+2.55196 3.20317
+8.1236 8.60951
+1.90437 3.23006
+0.888133 2.50365
+1.13618 1.69444
+2.60463 3.01696
+7.2311 7.73229
+5.06501 6.01487
+3.9893 4.10116
+1.45278 1.56937
+2.74601 3.80778
+9.40705 10.3843
+3.02533 3.52213
+8.7097 9.2268
+8.73145 10.5552
+2.56059 3.5742
+6.27328 7.57089
+3.23291 3.30811
+6.33804 7.20304
+7.63648 8.34564
+9.82053 9.93597
+3.14924 4.58629
+5.28253 6.33733
+1.99411 2.04104
+0.305593 0.420302
+5.39668 6.64188
+7.99992 9.37823
+5.25169 5.65987
+0.109291 0.875734
+3.08589 5.50296
+6.51358 6.62588
+5.34687 5.58204
+0.043587 0.932787
+-0.0264143 0.28677
+8.09722 8.37087
+5.46612 6.30285
+2.89146 3.49892
+6.73278 7.11762
+5.03068 5.90176
+1.7459 2.87727
+0.207707 0.448933
+7.00453 7.63105
+6.02789 7.87991
+8.1917 8.95854
+7.49014 8.73215
+8.48402 9.22063
+1.0467 2.4687
+0.241901 1.38802
+2.65867 2.81258
+5.46725 6.59448
+3.40578 3.75607
+4.2495 4.26392
+5.6608 6.213
+2.99705 3.88852
+6.17231 6.72018
+-0.17415 0.492739
+4.89596 6.49895
+4.68876 6.60218
+-0.0510568 1.46013
+8.87099 9.28179
+3.98894 4.5838
+-0.20015 1.59214
+8.80756 9.51828
+7.74921 8.53538
+-0.380041 0.440574
+2.69409 3.91466
+2.42747 4.56745
+6.25881 7.75647
+7.2941 7.77193
+2.60806 2.90251
+0.325028 1.22219
+8.29921 9.01416
+3.85524 5.45451
+5.2612 5.71877
+2.92849 3.73937
+8.6242 8.70808
+7.28153 7.35797
+1.65378 2.87917
+3.46034 4.24143
+3.99989 4.3199
+1.15266 3.60328
+4.8464 6.4887
+4.67021 4.68421
+6.96861 7.31554
+0.00723008 0.817047
+7.59589 8.88352
+5.56725 6.08465
+9.02409 9.19527
+5.81681 6.74193
+1.98221 2.98678
+8.76392 10.7646
+4.3903 4.50531
+1.0186 2.01838
+2.66674 2.74505
+2.41105 3.44579
+8.98295 9.18995
+8.14385 8.98779
+2.69613 3.60144
+0.445704 1.51319
+-0.634889 0.860409
+6.32737 7.10112
+7.88824 8.06838
+3.76271 4.43529
+7.66487 9.30221
+8.73974 9.59191
+3.08965 3.43006
+8.9518 9.96154
+0.727194 1.55228
+6.35214 7.12234
+2.71987 3.22996
+7.12786 7.4379
+-0.346107 0.837469
+8.47103 9.05987
+9.15744 10.628
+8.3237 10.093
+1.15052 1.16223
+6.95959 7.35423
+7.69488 8.44145
+4.21694 5.65913
+3.10562 3.37534
+9.73437 9.78252
+5.0458 5.53479
+7.80485 8.5163
+2.0442 3.75748
+-0.459177 0.498702
+7.38032 8.32195
+0.909659 2.11175
+7.08657 7.56877
+1.84997 3.10206
+4.2517 4.53819
+6.71655 7.04117
+1.06604 1.29153
+2.69273 3.31633
+2.19732 2.84826
+-0.723032 0.774865
+-0.289734 1.44645
+5.87194 7.71917
+1.01576 2.83685
+0.981927 0.998558
+3.07172 3.73201
+-0.112577 1.12642
+3.54063 3.67007
+7.21571 8.53815
+0.109957 0.839052
+6.86046 7.17211
+9.40878 9.69478
+0.989391 1.69046
+8.22287 8.8147
+1.48203 2.83308
+5.86418 8.0993
+0.749797 1.09852
+1.82996 2.50847
+0.28178 0.496017
+2.60694 3.00872
+8.6254 10.1698
+6.11641 6.41537
+7.19529 7.21342
+1.8214 2.17517
+0.991201 1.3788
+2.84924 3.12362
+5.75821 7.13843
+6.7106 7.35932
+6.6055 6.6829
+7.97105 8.58613
+1.56087 1.95845
+6.36782 7.10926
+2.43382 2.74699
+7.40509 8.8029
+8.42459 8.63142
+6.26128 7.55043
+4.6465 5.4431
+2.93214 3.29517
+0.157602 0.545214
+6.05931 6.72188
+1.7908 3.11731
+2.39217 3.58736
+7.07421 7.43852
+8.13419 9.74991
+9.53094 9.65319
+2.35726 3.68679
+-0.108561 0.874853
+6.87136 8.84157
+3.40803 4.58835
+7.50448 7.89932
+4.29762 5.53867
+0.863755 2.30032
+7.24847 7.95342
+2.89618 2.98849
+-0.928261 1.61922
+0.974105 2.91262
+6.99271 7.25856
+3.60995 5.01832
+1.26865 1.79704
+9.62217 9.80719
+1.02656 1.35514
+7.16502 7.32934
+3.12092 3.28857
+2.81374 3.84317
+8.73626 10.7585
+3.36982 3.61446
+5.08437 5.78949
+2.90218 3.0862
+9.2309 10.2523
+5.0967 5.48926
+9.73088 9.92708
+1.54013 2.78301
+6.73707 10.0789
+6.41735 6.838
+2.57935 3.04287
+5.719 6.70352
+5.42474 5.62732
+4.23904 4.69787
+4.16528 4.28736
+7.73477 8.84143
+4.90346 5.87324
+5.1969 6.14087
+3.48793 4.14182
+0.648493 1.07987
+6.88101 6.97932
+7.67342 8.74418
+5.16759 6.3871
+9.16292 9.49569
+8.77422 10.4817
+-0.358149 1.04178
+9.54616 10.3424
+3.12027 4.26504
+3.81223 4.73004
+1.2386 3.32247
+8.21963 8.42629
+9.10312 9.51016
+6.96107 7.43045
+2.98587 3.12365
+0.198165 0.211424
+5.19716 6.10856
+6.10553 6.3327
+3.98176 5.11099
+1.02512 1.04242
+4.27949 5.71947
+-0.457956 0.538807
+7.99877 9.48581
+5.88782 7.73303
+1.21496 2.85825
+8.46962 8.7862
+9.50182 10.1527
+5.85223 7.76234
+2.48368 2.52439
+2.35426 2.77405
+0.397056 0.482679
+0.160423 1.15786
+4.47109 4.8633
+4.74523 5.84196
+5.39177 5.75218
+9.00754 10.3249
+3.74813 4.03273
+3.08633 4.08426
+4.62672 5.29012
+1.92055 3.01442
+3.79279 4.5603
+9.52431 9.68334
+2.8126 3.32592
+-0.313688 0.490785
+9.06695 9.36835
+2.60321 4.14185
+4.40231 4.99535
+9.32205 10.1041
+5.3879 5.44349
+0.308728 1.0956
+9.05758 9.08283
+1.90313 2.50914
+7.1391 7.59459
+7.47357 7.95993
+1.25267 2.34827
+3.33222 4.36522
+8.78126 9.38611
+0.635979 1.62283
+8.3492 8.57545
+-0.572557 1.60517
+8.28855 9.03937
+3.47934 3.90271
+4.64498 5.43501
+0.872177 2.62011
+7.3893 7.58876
+2.14063 2.88063
+1.69361 1.75261
+4.19727 4.86483
+0.814676 1.27639
+8.19899 8.58203
+8.3394 8.99896
+9.31768 10.1694
+4.99218 5.19949
+4.2459 4.75266
+9.6314 9.64249
+4.038 4.75708
+7.92398 8.8579
+4.30747 4.54161
+7.51776 7.78258
+3.77611 5.1385
+3.53275 3.90278
+1.78619 2.12474
+3.18736 3.55159
+8.36759 8.52587
+5.52526 5.7843
+7.64174 8.09773
+4.37925 5.85699
+3.94295 5.31298
+-0.464623 0.795523
+7.02408 7.7048
+0.0690458 1.0008
+1.05445 1.32797
+0.126093 0.712612
+-0.809973 1.33869
+3.45568 3.96532
+0.433875 1.78679
+8.94667 9.65034
+1.98575 2.76936
+6.47974 7.67912
+2.74186 3.34153
+7.82655 9.32112
+4.71441 6.14932
+0.741177 1.76987
+8.05021 8.23239
+0.818503 0.882959
+7.13341 7.43399
+8.45939 8.93395
+4.44558 5.70161
+3.05657 3.86962
+8.75469 8.85537
+1.0922 2.23475
+6.00278 7.51598
+0.0530968 0.582206
+4.01788 5.48223
+1.30808 2.81869
+8.18848 8.59771
+2.43691 2.80685
+8.54045 10.6178
+7.58523 7.91634
+6.70183 7.49962
+5.81501 7.29783
+0.661853 1.58021
+6.50997 7.20411
+0.334292 1.40252
+-0.329585 0.742961
+2.38756 2.48935
+2.78114 3.58788
+7.97227 8.55379
+3.36753 4.57472
+5.14486 5.31457
+3.99691 5.47708
+6.36404 6.8741
+3.22519 4.63321
+1.80583 2.21824
+8.20747 9.42947
+5.90819 6.94368
+6.58559 6.85933
+2.99108 4.03832
+7.20963 9.6252
+3.10244 3.87265
+7.23018 7.91389
+7.18084 9.61063
+6.74145 6.86507
+8.40721 9.5751
+7.12352 9.45614
+2.06653 2.51786
+4.9155 5.04183
+1.34304 2.92777
+0.571315 1.17285
+8.05396 8.28214
+5.29142 6.24974
+8.93797 9.23051
+4.6108 5.45568
+6.46124 7.53124
+3.16695 4.37505
+2.76803 2.82764
+4.1531 4.84927
+8.19433 9.00383
+5.12114 6.22952
+2.2542 4.74849
+0.621192 0.871537
+1.37403 2.28895
+0.305704 1.3287
+8.70471 9.53085
+2.29164 3.56607
+2.42106 3.37382
+1.14309 2.03085
+9.17624 10.3281
+1.88864 2.70161
+0.932647 1.2473
+5.72385 6.55694
+5.25496 5.38675
+5.85771 6.69626
+7.37247 7.93094
+7.73499 7.98782
+4.91417 5.27506
+3.51127 3.84403
+6.96198 7.27686
+6.51176 7.74735
+4.19954 5.08222
+1.58115 1.83842
+2.11889 2.3408
+1.94427 2.00422
+5.59977 6.86555
+9.46942 10.3491
+9.18904 10.1988
+1.71938 3.01547
+4.3515 5.4951
+2.53792 5.85188
+0.3884 1.36228
+5.02469 5.62368
+6.82402 7.72203
+-0.320478 0.821539
+0.0885656 0.248783
+3.01725 3.44385
+6.63776 7.74386
+6.57899 7.9332
+4.82656 5.18327
+3.91909 4.43955
+0.0708319 0.101395
+2.59796 4.22775
+-0.433109 1.26978
+-0.434274 0.624336
+3.22018 4.25282
+4.63351 4.776
+8.889 9.56332
+5.35952 5.46531
+8.73832 9.22756
+2.03432 2.34194
+0.477994 1.43353
+1.2029 2.86844
+5.09945 5.76855
+8.89076 9.01771
+5.30284 6.31732
+1.56375 3.17543
+5.4773 6.36897
+5.30934 5.35073
+7.20096 7.7075
+6.51046 7.12888
+9.37127 10.0531
+-0.0484323 0.348687
+1.83241 2.2143
+8.28633 8.60462
+2.51014 3.65817
+3.27798 3.58685
+1.41567 2.23302
+7.50794 8.10378
+-0.0579575 2.10373
+-0.856005 0.96621
+2.96238 3.48434
+1.36304 1.90594
+2.9997 3.41214
+7.2763 8.087
+1.69207 2.74419
+5.41625 5.83917
+9.22139 9.53794
+1.17477 1.51576
+6.74597 7.90871
+0.678913 1.73759
+5.70863 5.7214
+8.88411 8.93377
+3.44409 4.54586
+0.958963 1.53878
+8.29904 9.3867
+2.52433 3.60238
+8.16257 8.21986
+2.11395 4.23455
+6.85451 7.40364
+0.20286 0.639736
+2.05848 2.49034
+0.547013 0.77336
+7.83609 8.11903
+2.16539 2.29286
+3.94232 4.31368
+8.53475 8.54519
+4.77462 6.4158
+4.08395 4.68214
+1.56902 2.23811
+1.61337 3.11768
+1.51181 1.65521
+0.0821202 2.09269
+4.77622 5.16243
+4.62148 5.75837
+0.613158 0.952696
+1.89128 3.04792
+7.57509 8.92834
+2.70465 4.2941
+4.95906 5.12442
+8.0927 8.17277
+0.796512 1.3215
+5.74134 6.45291
+9.68479 9.78978
+5.89261 6.2292
+6.11377 7.9339
+2.20571 2.67129
+3.46228 4.27058
+5.26723 6.2653
+4.04391 4.26562
+0.380382 0.818995
+7.58108 7.7618
+5.02375 6.13042
+4.20178 4.66297
+2.83039 3.0221
+2.36072 2.45545
+6.68854 9.20726
+2.91388 3.42464
+9.33373 9.73449
+7.75844 7.94625
+2.72414 2.89669
+6.65438 7.96623
+1.00647 1.05385
+2.63018 4.9432
+0.152187 1.60259
+8.86332 10.3631
+2.31523 2.6815
+8.00509 8.61794
+1.69711 1.75938
+8.65442 8.73697
+4.23917 4.32001
+9.66851 10.1925
+6.93943 7.49814
+8.51986 9.03561
+2.10317 2.5175
+0.539549 1.75683
+6.29423 7.93236
+8.64345 9.54556
+1.44069 1.6814
+9.10017 9.77088
+6.16731 7.40496
+0.570043 1.93192
+2.65761 3.88544
+1.46895 1.52688
+-0.369067 0.540647
+2.04868 2.72065
+2.1286 2.27858
+5.90157 6.16431
+1.55581 2.51851
+3.29705 3.81635
+3.4137 4.10991
+8.48699 10.1364
+8.43437 9.4642
+-0.037842 1.47589
+0.541735 1.7805
+0.499576 2.36065
+4.1415 4.72435
+4.77598 6.16872
+3.30388 3.61854
+6.43796 7.85966
+5.27157 5.70871
+0.919258 2.18653
+4.00961 4.07902
+3.78201 4.23596
+4.50464 4.791
+3.70253 5.30916
+8.59228 8.70036
+4.31103 5.69049
+5.31775 5.34378
+2.24198 2.64194
+6.66937 7.41675
+7.21753 8.42057
+4.35399 4.52398
+6.90698 7.30084
+3.44296 5.44378
+3.36719 4.89951
+3.38624 5.33856
+3.44877 3.53693
+5.81398 6.3016
+7.24655 7.33127
+3.86142 4.53134
+3.85894 6.88112
+6.45704 6.95699
+6.90997 8.24088
+5.68813 5.7611
+0.699911 0.824323
+6.73758 8.42517
+9.34644 10.07
+0.289929 1.30554
+8.30644 8.49113
+6.47667 7.16073
+4.28093 4.90236
+8.32678 8.57064
+7.09205 7.92316
+5.55599 5.63919
+1.0104 2.22875
+1.72237 3.53668
+2.54699 3.14823
+-0.668582 1.25485
+1.25582 1.37003
+1.35044 1.57807
+6.17083 6.30811
+0.618816 1.20065
+-0.540992 1.21634
+2.06673 4.28857
+9.03398 10.8112
+8.73735 9.22814
+1.30178 2.7599
+6.0221 7.34889
+8.30124 8.52159
+1.92023 3.34545
+2.99331 4.93358
+3.8412 3.93379
+1.455 2.77005
+0.538664 2.1118
+4.16926 4.26053
+0.699746 0.937609
+6.36024 6.6511
+2.34698 4.84463
+8.11109 8.76496
+4.05425 4.67773
+8.2284 9.78568
+1.64423 1.80353
+5.70109 6.93764
+7.2091 9.67224
+4.47015 5.23311
+4.29326 5.36144
+7.93151 8.96494
+4.61889 4.96487
+5.38473 5.43594
+9.35456 9.66489
+1.23737 3.04121
+1.16077 1.19519
+5.91037 7.55679
+6.88344 7.60181
+6.39705 8.65039
+1.61791 2.93041
+9.68285 10.1396
+9.03129 9.05839
+7.0683 8.29875
+7.19624 7.41696
+7.5266 8.38738
+-0.254571 1.01098
+1.30218 2.03222
+7.6432 7.73031
+4.99495 6.04757
+2.79394 3.29394
+0.31505 3.55963
+7.55382 8.18787
+6.00032 6.27664
+1.49355 1.79767
+5.21191 7.19537
+3.47816 3.75801
+2.10272 2.39494
+1.31887 1.93829
+7.14313 7.63055
+7.3141 7.77239
+6.03409 6.17265
+4.24946 4.53165
+0.0569272 2.56109
+8.44766 11.4872
+4.22879 4.28007
+6.92817 6.98775
+8.08859 9.0206
+-0.0748418 1.48605
+6.56698 7.0488
+4.46624 5.4952
+3.66085 4.05778
+6.44711 8.93943
+2.45735 2.49339
+0.0606673 0.416191
+-0.183838 0.750464
+7.08561 7.67275
+6.65423 6.90808
+0.0598735 0.364072
+5.2228 5.41543
+3.14042 3.19043
+2.40069 3.02829
+1.80441 2.1849
+3.47491 3.95775
+5.49162 6.63934
+2.03332 2.32288
+3.17234 5.25109
+2.58274 2.59951
+9.37994 9.97097
+4.71509 6.77966
+5.18915 6.84982
+6.12508 7.04354
+0.811202 1.98808
+1.46825 3.66984
+2.44386 4.15623
+7.60169 7.68242
+-0.43208 1.22222
+5.40569 5.66153
+0.391742 1.79408
+6.77742 8.43115
+9.12828 9.3851
+6.39541 6.80626
+5.17919 6.29326
+6.57263 8.12999
+3.439 4.62236
+8.40525 9.80086
+7.60986 7.70099
+1.32123 1.44213
+0.526574 1.92338
+9.57195 9.79591
+9.52103 9.63159
+3.79775 4.20608
+4.74446 4.89606
+9.00085 9.60025
+1.26279 2.08363
+4.13639 4.49232
+6.59409 7.18315
+1.0637 1.78425
+5.4213 6.87661
+4.24407 4.30987
+9.79732 10.1204
+4.24597 4.83541
+8.47705 8.5145
+4.34095 4.93842
+5.68168 6.96086
+7.48654 7.91072
+8.32005 8.45111
+5.24065 5.3032
+3.25982 3.94442
+5.58106 6.18764
+4.4243 5.58619
+6.36467 7.07082
+2.70051 3.56014
+5.94534 6.87688
+7.33638 7.7645
+4.57067 5.86652
+7.83993 8.36854
+9.03617 9.11629
+7.44672 7.95614
+6.05876 6.3594
+4.02496 4.97119
+3.01438 4.36109
+7.4932 7.92357
+7.51661 7.53354
+7.60692 8.49678
+1.76088 2.59103
+7.08578 7.39566
+4.83605 5.42933
+-0.186592 0.847663
+1.15879 2.33996
+8.11815 9.35472
+6.02584 7.62549
+0.881084 1.00015
+5.39067 6.27026
+0.910755 0.97444
+5.32174 5.65652
+7.69388 8.24928
+3.40521 3.7615
+5.60321 6.92388
+8.25096 8.34324
+0.00108913 2.16897
+0.508035 0.66573
+-0.0517816 0.0876197
+3.26472 4.30955
+1.99494 2.14903
+2.089 4.32368
+5.17378 5.75964
+2.8779 3.54361
+6.56459 6.90645
+1.43196 2.88337
+1.48917 1.94009
+3.40807 4.25784
+8.0334 8.13458
+8.22254 9.6175
+2.96308 3.14349
+5.04768 5.71252
+3.9977 4.72614
+1.44384 1.60782
+7.78147 8.19817
+7.03854 7.50085
+5.90747 7.06091
+2.89169 4.31831
+2.46167 3.16529
+9.13228 9.1504
+2.57975 3.05313
+5.75976 6.52958
+8.10499 8.98982
+8.43162 8.76377
+0.422917 0.668254
+1.69046 2.09962
+5.50386 6.66954
+0.0897183 0.564514
+3.50103 4.1041
+3.91918 4.52559
+4.39297 6.18876
+3.90396 4.90868
+9.69362 9.85528
+6.27994 6.95062
+8.01563 9.09433
+8.25641 9.72944
+8.22072 8.35423
+1.27059 1.61352
+8.53312 8.96235
+3.49185 3.9042
+5.79579 6.046
+0.489013 1.2147
+4.00074 4.177
+2.66625 2.93036
+7.20267 9.34958
+7.44659 8.54707
+8.99915 10.1143
+7.59922 7.82031
+8.38502 9.03222
+0.160075 0.294398
+4.14549 4.3927
+9.35554 10.248
+-0.159435 0.467922
+2.17272 3.72336
+8.63811 8.79976
+4.23215 4.66461
+6.99516 8.2035
+6.45212 7.88791
+6.20141 6.28633
+7.69396 8.82204
+4.50807 5.96315
+8.51725 8.89286
+0.939492 2.12064
+7.4615 7.62666
+8.46681 9.11769
+3.92828 5.40884
+9.05622 9.40015
+0.229625 0.860838
+2.05694 2.52113
+-0.217927 0.574255
+9.55146 10.3256
+8.31497 8.3417
+3.52833 4.47013
+7.7131 8.52058
+2.15462 2.66777
+5.7674 6.17553
+3.3358 4.10589
+2.06642 3.00412
+2.43387 2.85242
+5.09473 5.84276
+7.3287 7.54846
+4.64254 5.11465
+4.05785 4.93614
+4.25413 5.43513
+2.96476 3.15378
+3.53732 4.48239
+2.34137 4.01272
+2.24879 3.40626
+3.43323 4.49055
+0.871415 1.33068
+0.508929 1.65611
+4.92057 4.94743
+7.03376 7.35193
+5.73043 6.47264
+7.82417 9.93642
+5.24102 5.9178
+2.38528 4.1676
+6.27437 7.19631
+9.29267 9.53262
+4.10098 5.24964
+0.383714 0.833317
+5.97628 7.92987
+8.15799 8.96819
+8.1687 8.29862
+8.16289 10.5149
+7.38205 7.89765
+3.81883 4.15607
+9.46915 9.61755
+1.50756 1.51863
+2.34236 2.84689
+0.398473 1.15027
+1.05302 1.49155
+8.71687 9.35232
+1.0502 1.40395
+7.83685 8.76302
+7.7731 8.46899
+5.56618 5.97458
+2.90035 4.12043
+6.40644 6.68706
+3.95201 4.37075
+7.1831 7.67748
+9.42789 10.0914
+5.45198 7.01256
+8.64609 9.45756
+6.01864 6.31515
+7.64621 8.65533
+5.45654 5.76553
+2.04332 2.75476
+5.49454 5.85693
+6.13688 6.21927
+2.66255 2.7385
+4.8326 6.43772
+9.12704 9.45287
+-0.294488 0.318697
+2.26979 2.35516
+4.12949 5.58506
+3.01416 3.62246
+6.64697 7.10221
+6.44307 6.82985
+4.10484 4.73148
+7.42589 7.6029
+5.33055 5.50395
+2.46474 3.05847
+5.43677 5.59206
+2.13807 2.3988
+-0.38424 1.8121
+0.00916704 0.219304
+8.62621 10.2262
+3.33927 4.51169
+5.45656 7.13165
+5.29253 6.57917
+3.51704 3.9421
+8.63729 9.13361
+3.92626 4.3469
+6.83104 7.52695
+1.22258 2.28191
+0.447646 0.789809
+7.96543 8.54328
+2.24269 2.42571
+4.4161 5.40481
+0.813992 2.21792
+0.694664 0.974182
+6.50017 6.88902
+4.00723 4.65882
+9.05784 9.85062
+6.80276 6.98196
+0.105446 0.379881
+0.416982 0.53336
+9.01269 9.55204
+3.27197 4.23315
+6.7017 6.89704
+4.21512 4.42378
+4.86735 6.90949
+4.52235 5.36878
+2.62205 3.55746
+-0.551048 0.555476
+1.63274 2.71251
+4.26739 4.88085
+8.23129 9.77405
+2.49409 3.96851
+6.66387 6.88886
+7.72383 8.90611
+3.18511 3.27281
+0.73722 1.64435
+7.90329 9.02868
+6.94845 7.06773
+0.509461 1.54928
+4.63885 5.51652
+9.24395 9.5121
+1.00007 1.57161
+5.31349 5.45437
+0.929284 1.71034
+7.05985 7.63288
+7.38418 7.45373
+4.14937 6.5167
+7.49989 8.6081
+9.28313 9.57721
+4.41285 5.1497
+2.96148 3.09221
+1.58256 1.66419
+4.45116 5.43488
+5.70927 7.11699
+3.61105 3.93153
+5.92285 6.63773
+3.50065 4.48453
+7.97338 8.96464
+0.541394 0.965435
+4.46469 5.03925
+7.33695 7.6484
+9.64234 9.6938
+4.16378 4.17886
+7.10741 7.31549
+1.51829 2.62477
+2.1892 2.9684
+9.23767 10.0462
+7.87649 7.97087
+7.05385 7.85952
+6.91232 7.50277
+6.60185 7.81572
+2.27112 3.90211
+5.74452 8.2018
+6.25117 6.26911
+0.525893 1.53447
+0.392956 0.959233
+3.51591 4.71055
+3.10449 5.41156
+7.35964 7.65642
+2.89831 3.54334
+3.42338 3.68259
+4.75496 5.51419
+3.8792 4.48395
+2.18007 4.13236
+3.15798 3.16864
+8.91248 9.21598
+8.54636 9.34037
+7.93697 9.79709
+6.40205 8.9653
+9.67332 10.2252
+4.31771 5.25423
+7.27485 7.3725
+6.22971 7.11411
+1.16538 2.16762
+1.40443 1.6876
+3.14915 4.58847
+7.13761 8.72165
+4.38448 5.88699
+7.98309 9.19449
+8.491 9.05597
+5.55043 6.19359
+2.44006 3.36071
+9.56522 9.79903
+1.86129 2.00225
+1.65239 2.11478
+7.59392 8.4655
+2.44709 2.68538
+6.80932 7.04694
+8.8212 9.4182
+0.276845 0.956468
+8.17008 8.5538
+0.77864 2.06897
+6.78458 7.68692
+0.504907 2.67518
+5.56963 6.9058
+3.42691 3.5414
+2.52065 2.71583
+5.09924 6.26696
+0.223724 0.610039
+3.61258 5.29324
+0.388393 3.11131
+2.87763 4.45415
+8.26438 10.1169
+5.89742 8.17506
+1.89686 2.66651
+5.33662 5.68228
+3.37496 5.67291
+2.25713 2.36127
+0.402185 0.716342
+6.4231 6.79227
+3.22707 4.69314
+7.85092 8.77413
+3.31322 3.72455
+5.43021 7.7167
+8.5883 9.00864
+1.21371 1.71836
+6.35584 7.9706
+5.44438 5.50414
+5.31325 6.11217
+6.08888 6.78794
+7.70604 8.13257
+1.29858 2.48753
+5.54083 6.38817
+8.23948 9.82646
+7.5575 9.0224
+8.00415 9.39763
+0.488455 1.55358
+4.48727 5.20741
+6.46648 7.02349
+0.355939 0.611119
+9.4892 10.2189
+2.61893 2.82832
+0.268193 1.24687
+3.01964 5.19554
+6.29954 7.42795
+8.70796 9.48366
+5.39307 6.64597
+2.47001 2.60746
+5.30949 7.46529
+6.07973 6.16835
+0.764507 1.6144
+7.94123 8.52143
+1.88244 1.96592
+6.42103 7.02205
+7.673 7.73208
+6.66891 7.80675
+6.9305 7.5431
+6.62335 6.93873
+4.34846 5.77621
+0.49878 2.82928
+2.65221 2.80109
+7.45348 7.74372
+4.10129 5.26894
+3.87782 4.19855
+4.62113 5.22658
+2.84558 2.88185
+2.53209 2.86065
+8.94932 9.21967
+6.48046 6.89614
+5.81885 6.66829
+6.49129 6.62015
+8.5663 9.58685
+2.43346 3.89849
+9.36561 9.45886
+1.40232 2.65
+6.66 6.74041
+2.87007 3.49668
+4.71138 6.0184
+5.03638 6.08494
+7.77735 8.14253
+1.0301 1.27179
+2.58337 4.04699
+6.95419 7.89775
+7.81164 8.62551
+3.37669 3.96217
+4.68541 5.58692
+4.79697 6.34841
+3.95334 4.81962
+9.44006 10.0941
+4.91098 5.12386
+8.44273 10.1565
+3.6685 3.73156
+5.07599 5.33357
+-0.138235 0.260923
+2.71154 3.45603
+5.75096 6.16127
+4.4775 4.64308
+6.80557 8.97442
+5.49408 5.76652
+8.31937 9.12886
+3.26479 5.51673
+2.57425 3.03145
+2.42465 3.92714
+7.86505 8.50835
+3.29229 3.43549
+4.08537 4.69709
+7.83885 8.60616
+1.61622 2.72716
+9.10228 9.41907
+8.49325 9.46612
+-0.174644 0.351716
+1.95648 2.14825
+8.28844 8.4428
+4.35888 5.59521
+5.1396 5.22537
+0.330835 0.879566
+6.14972 6.82967
+3.14811 4.89049
+-0.231668 1.08277
+3.13526 4.94545
+8.32674 8.91046
+5.22364 5.48006
+9.84318 9.88416
+-1.07813 1.6965
+1.5095 2.0328
+8.03716 8.2792
+-1.01307 1.46703
+8.22096 9.0055
+8.9917 9.0415
+5.60623 6.74537
+3.15991 3.19314
+3.13863 3.26451
+0.739618 0.896958
+0.67599 1.18486
+3.37355 4.06303
+0.38605 0.410067
+3.03297 3.46387
+3.45867 3.79806
+8.67249 9.53278
+-0.213855 0.787363
+1.52316 2.61117
+8.31846 8.59736
+4.84685 4.94042
+7.41901 7.82623
+4.99029 5.09747
+5.3637 5.37612
+3.22123 4.77749
+3.21668 5.74743
+3.48748 4.59962
+8.00016 8.56269
+1.63631 2.42239
+1.05159 3.72319
+7.22643 7.95706
+5.65694 5.99195
+9.4469 9.66915
+0.857984 1.59867
+4.05869 5.69955
+2.65788 3.07259
+1.8038 3.38748
+3.91934 4.89922
+6.18534 6.70342
+2.85076 3.20176
+8.1897 9.9614
+0.685531 2.05322
+3.31097 4.00809
+8.26537 8.63475
+2.90508 4.07797
+1.25213 2.31285
+3.05752 4.03741
+-0.481913 0.605629
+1.87958 2.19386
+7.28689 7.76316
+4.82075 5.20688
+-0.08115 0.31839
+3.50085 5.89363
+1.31184 3.30269
+4.03137 4.81493
+6.11688 6.13923
+7.93584 8.43321
+4.9838 5.3733
+3.8174 4.11979
+8.56196 9.02824
+2.87809 3.89589
+7.95309 8.05432
+3.47469 3.63716
+6.61009 7.12576
+8.87374 9.79588
+7.31513 7.99089
+5.78084 6.68535
+4.96985 5.59877
+2.20236 2.52473
+0.661014 1.11035
+6.36183 6.58403
+6.67947 6.85093
+-0.242005 0.513902
+0.442966 1.72024
+6.4587 6.74016
+6.67958 8.0837
+8.98524 9.56405
+6.91409 7.59877
+3.73596 3.97705
+5.51193 5.96437
+3.72029 4.50126
+3.09896 3.23616
+8.83312 8.91774
+0.32173 0.486199
+4.21092 4.59955
+2.61616 4.07081
+1.89049 2.65559
+4.96401 5.00629
+9.33156 9.70914
+3.72455 4.61054
+8.91265 9.6563
+7.12401 8.04324
+6.65393 7.25572
+1.04032 1.24927
+3.0174 5.56006
+1.47645 2.26867
+3.49833 4.37416
+6.16877 6.34452
+6.47417 6.90595
+4.27056 4.92535
+7.60439 9.35352
+0.426219 0.754405
+8.5291 8.68579
+5.84717 6.64632
+1.99513 2.5284
+5.10669 7.83064
+6.99006 7.37272
+0.871836 1.5934
+3.6572 4.38875
+0.154617 0.290737
+5.91634 6.50415
+5.33982 5.45293
+6.92602 6.94691
+0.349512 1.61427
+8.02048 8.99943
+5.75598 7.34946
+5.86948 6.51327
+5.11707 5.6181
+6.27656 7.10043
+8.48922 9.73833
+8.35863 8.69746
+6.67829 7.07852
+8.51257 9.50383
+3.76636 4.33757
+4.82804 5.57166
+5.17892 5.61254
+1.35188 1.94069
+6.04969 6.06833
+5.34181 5.82455
+5.71714 6.71234
+0.966462 2.56278
+7.95169 8.15951
+6.53583 6.89673
+6.73246 8.34493
+8.71111 9.76467
+7.53215 9.56537
+0.619041 0.736713
+9.24399 9.50151
+8.57184 9.88538
+2.82682 3.77294
+4.2649 4.84602
+8.6621 8.96426
+8.04469 8.3189
+7.81877 8.42944
+2.78031 5.16589
+1.23076 1.43577
+8.35385 8.49632
+3.27901 3.66774
+0.595941 1.41354
+3.37123 5.16685
+9.11003 9.95515
+-0.25959 0.32069
+1.44153 1.70148
+1.61595 1.70799
+7.8201 8.53423
+8.5402 9.36947
+8.39125 9.8221
+6.2909 6.35773
+0.000933745 0.920054
+-0.21358 0.491025
+4.00874 4.03866
+3.43552 3.55874
+7.85942 7.98987
+7.6681 8.06748
+6.19541 7.14765
+8.53891 8.96393
+2.38789 3.26866
+-0.0162847 1.18379
+1.04764 1.52755
+0.400798 0.55475
+6.32001 6.94897
+5.9692 6.2012
+1.20784 2.67873
+3.58247 4.46372
+-0.229647 0.559407
+5.65979 5.73489
+2.32795 2.78462
+0.706144 1.55147
+4.56527 4.6636
+5.98901 7.20908
+9.27329 9.95152
+1.31296 1.70529
+5.82933 6.41329
+4.17452 5.29881
+4.15885 5.25117
+0.35549 1.3511
+1.0591 2.4463
+8.87597 9.55625
+6.66826 8.57255
+0.355945 1.40613
+5.39729 6.10218
+3.78791 4.37501
+9.53885 9.87184
+2.67568 2.82552
+4.44836 4.52939
+5.96764 7.40168
+6.35578 6.98546
+0.636857 1.19517
+3.3986 5.55448
+1.46493 2.66884
+-0.0676901 1.80921
+7.83396 8.53452
+8.3508 9.04561
+4.03407 6.0066
+0.997538 3.30635
+7.83064 8.03466
+4.57652 4.97461
+3.85952 4.15471
+0.960261 2.1069
+0.522458 1.52989
+8.81627 9.00768
+0.172256 1.29455
+5.69294 6.15752
+6.86391 7.75307
+2.32429 2.95415
+1.83191 1.90364
+0.400855 0.705649
+5.23264 5.39972
+5.19047 5.79842
+2.40804 2.89401
+0.462887 1.43874
+6.70213 7.90229
+4.37985 4.95797
+3.73768 4.30645
+0.756797 2.11146
+0.458724 0.472099
+3.93098 6.47147
+5.5294 6.00365
+2.97106 3.42174
+5.75875 5.80235
+7.96799 9.02105
+5.36254 7.22823
+6.56124 7.39973
+9.49234 9.57879
+2.87576 3.59509
+3.49182 4.28124
+8.68021 9.94486
+9.60199 10.1276
+9.70115 9.81776
+3.09609 3.98732
+5.00113 8.15031
+5.21248 5.74835
+9.23337 9.5696
+2.92777 3.56297
+2.52044 3.04905
+4.79908 5.05762
+1.98626 3.69659
+4.78726 6.20637
+7.39711 7.42831
+4.44319 4.78716
+9.28452 10.0832
+8.00774 8.85707
+9.22947 10.0523
+4.38653 4.86012
+5.15285 5.23106
+8.95413 9.75947
+2.90286 3.32407
+0.348694 1.39738
+-0.0660432 0.293424
+4.09079 4.2922
+6.0407 7.23031
+2.83771 3.72237
+8.54697 9.38898
+2.16742 3.45018
+8.83255 9.30343
+3.59112 3.6531
+7.53452 7.81898
+7.11781 7.19773
+8.2892 10.0259
+4.91072 5.06031
+5.8232 7.25924
+7.0641 8.31604
+9.477 9.63892
+5.8003 6.58306
+9.63988 10.2754
+0.654364 1.02398
+5.9488 6.85043
+7.86867 8.99891
+9.202 9.46902
+4.17932 4.20271
+6.50328 6.71085
+7.19848 8.15579
+5.62459 5.75449
+-0.159668 0.791409
+7.55683 8.7315
+1.03278 1.423
+0.751457 0.808785
+6.2203 6.50634
+1.64418 2.98238
+6.87468 7.00652
+6.36966 6.7117
+7.69893 8.89535
+0.419794 1.05032
+2.73928 4.31548
+0.409245 1.55228
+6.03905 6.39323
+0.409695 0.789834
+4.39148 4.40935
+1.14673 3.23607
+5.85562 6.44503
+6.87394 6.88742
+3.761 4.35136
+7.2208 8.01436
+6.49839 6.54002
+4.70791 5.91886
+4.24906 5.96619
+2.53482 3.91496
+-0.369254 0.69193
+4.81351 6.31088
+9.76066 10.0736
+1.4413 1.55942
+7.21917 8.88908
+6.03521 7.56826
+1.25568 1.42024
+5.47575 6.04431
+1.43099 1.99979
+5.1004 6.04088
+6.54798 6.56118
+1.0142 3.1564
+1.75267 2.1453
+1.28133 1.36044
+9.60996 10.0563
+1.14397 1.50247
+6.86688 7.08724
+8.38287 9.18041
+0.132076 1.27657
+6.52553 6.9301
+0.223917 1.41325
+1.18902 1.79753
+1.40084 1.75678
+1.94524 2.51929
+1.98276 2.62875
+0.763281 1.05483
+7.97952 8.51249
+1.059 3.05463
+5.33401 5.85094
+8.37442 8.64374
+6.62865 6.67315
+1.01707 1.64386
+0.113335 2.23523
+6.71906 8.00216
+-0.886574 1.29366
+4.20078 4.85294
+8.43336 9.06988
+3.55413 4.40768
+6.69076 9.01132
+6.18982 7.14109
+7.14381 7.7046
+8.63195 9.47031
+8.88052 9.84886
+3.34443 3.62637
+4.5862 4.72832
+4.95757 5.23571
+2.85993 4.04966
+1.43846 2.27425
+5.43112 6.30496
+-0.452609 1.55525
+7.17706 7.71287
+5.78537 5.79579
+8.51102 8.9466
+-0.472904 0.810489
+3.83688 4.24045
+8.04432 9.04582
+1.57259 3.37136
+1.22231 1.33582
+5.73006 6.26477
+2.90855 4.22125
+9.39717 9.4287
+3.63873 4.16094
+0.442035 2.08889
+0.294491 1.31124
+3.14755 3.86305
+6.57634 9.44898
+2.19051 2.41878
+4.99277 5.12569
+4.10425 4.9423
+4.83547 5.62769
+5.73879 5.78179
+8.90329 9.81905
+5.60168 6.17538
+5.83843 6.66128
+1.84271 2.57406
+3.01047 3.33662
+2.85037 3.79158
+3.49007 4.46877
+8.58942 9.51529
+0.613753 1.12824
+8.23757 9.54707
+9.27134 9.4196
+6.27126 6.56417
+2.17206 2.33018
+3.53588 5.17162
+8.6312 10.0868
+5.76342 6.66164
+9.01501 9.90984
+3.22004 4.18954
+4.37918 4.68595
+2.00928 3.49815
+6.64229 7.06693
+2.85962 4.58794
+8.45587 9.8897
+2.8481 3.65956
+8.65849 8.67336
+6.48486 6.58637
+5.82336 7.45254
+4.02267 4.59696
+2.24997 2.83815
+8.16201 8.55518
+7.40645 9.07085
+1.43137 1.50333
+8.7212 10.9419
+1.50523 2.44124
+1.92455 2.85819
+4.50866 4.53052
+5.75781 5.81275
+1.71013 2.0282
+9.31592 9.9015
+6.14972 8.18798
+1.85705 2.20068
+4.80971 5.10509
+3.31201 3.58168
+8.61824 9.31861
+7.19497 7.86933
+3.25381 4.53472
+5.62799 6.29537
+9.00659 10.021
+9.15156 9.74827
+2.0324 2.80741
+0.714403 1.00476
+1.26522 1.80417
+-0.362995 0.41758
+7.08785 7.71544
+5.55685 5.74045
+0.428866 3.03773
+7.61574 8.94894
+9.07256 9.69772
+4.49537 5.06822
+5.66388 6.48899
+1.69126 2.69607
+9.90539 10.0783
+6.56455 8.27128
+6.61988 7.86616
+7.42012 7.64493
+2.99922 3.35282
+4.69379 5.18947
+0.87894 1.30518
+9.47632 9.61234
+0.665754 0.855958
+-0.422778 2.11197
+3.38786 4.15441
+7.57236 8.75855
+1.89832 3.50224
+-0.185929 1.0777
+3.32911 5.53465
+6.91111 8.69247
+6.97456 7.86905
+4.75518 5.0948
+4.23733 5.83368
+8.52456 8.56086
+0.0978267 0.136564
+7.4668 7.99757
+5.52851 5.80858
+8.5833 8.88589
+5.10603 6.41348
+4.70682 6.59981
+8.60265 9.19477
+5.04514 6.24014
+4.49041 4.88669
+7.40925 9.15624
+0.80364 1.35315
+7.11604 8.01153
+0.267749 0.714089
+0.121521 0.822226
+9.30556 9.81307
+2.11398 2.92567
+5.97722 6.08022
+7.13483 7.22211
+8.00161 9.27274
+4.87681 5.51654
+3.11843 3.84311
+5.17747 5.98482
+3.6077 4.46306
+1.37454 2.2443
+4.93385 5.96357
+2.92184 4.0964
+4.88767 5.56353
+2.87394 3.76336
+0.326521 0.622872
+2.42056 2.45007
+-0.527891 0.827211
+6.73151 7.20155
+1.82048 2.54905
+1.35563 1.88701
+3.64202 4.10669
+5.22846 5.23953
+6.06271 6.46993
+2.71418 3.2081
+6.41179 7.57176
+7.45823 7.79609
+1.01227 1.39137
+9.0872 9.20132
+5.083 5.64038
+5.63236 5.97945
+-0.317645 0.822313
+0.865396 2.65587
+5.71839 5.98983
+1.50978 2.08611
+2.95824 3.70996
+0.264301 1.02233
+8.22351 8.98589
+4.87805 5.24127
+2.31329 3.46752
+6.19539 6.69676
+5.18643 5.40947
+7.15453 7.66643
+1.20694 2.25111
+7.87378 7.89093
+5.16514 5.604
+8.68354 9.01395
+7.33753 9.37499
+2.94627 4.06036
+8.64337 8.85727
+0.0353092 1.0128
+6.98437 7.35718
+6.77073 6.79959
+3.13559 3.70735
+7.40139 8.27017
+4.01174 4.39788
+3.22281 5.11647
+7.79256 8.58737
+0.642233 1.39694
+7.18603 8.69453
+3.37803 3.59355
+0.762287 0.84262
+4.21823 4.52565
+0.894924 1.35434
+0.844327 1.19938
+5.57958 7.05431
+-0.631066 1.55134
+3.78962 4.17935
+9.15329 10.4824
+5.47536 5.52975
+8.81243 9.16088
+4.45989 4.94123
+8.68235 9.45112
+8.04719 10.3938
+8.87349 9.40483
+0.502543 0.570283
+2.08512 2.47652
+-0.654512 0.804355
+3.68569 5.21711
+5.33017 5.80226
+3.44991 5.31415
+-0.00417763 2.95077
+7.17784 7.9318
+1.2721 1.31642
+5.24415 5.64173
+2.79434 3.28746
+4.54991 6.49276
+4.74707 5.12555
+7.36365 8.15777
+0.913049 1.79828
+1.47498 1.83425
+2.64271 3.38567
+4.78159 5.44718
+7.6087 7.66442
+-0.484393 0.909893
+3.16824 3.23757
+4.43021 5.90284
+4.25954 4.74995
+6.58742 7.24125
+1.86151 2.27069
+3.16459 4.5945
+1.06471 2.08965
+3.31028 3.83029
+1.52593 2.47521
+0.703789 1.42451
+1.47969 1.68923
+2.92352 4.24089
+9.84088 9.93485
+3.18205 4.27817
+7.39345 7.78945
+3.78808 5.41572
+4.38624 6.75693
+6.93065 7.16977
+1.01289 2.19807
+3.37006 3.54196
+5.50238 5.58285
+-0.225113 1.99347
+1.67796 1.86943
+6.1999 6.35102
+3.80494 4.74814
+1.13294 2.02639
+1.1965 2.6548
+-0.284453 0.856092
+4.26565 5.02196
+9.66948 9.88874
+6.20287 6.25528
+4.38154 6.65806
+3.77411 4.3075
+5.77177 6.78486
+9.16311 9.816
+3.22861 3.42009
+3.36573 4.34724
+6.76951 7.58025
+4.83813 5.23042
+3.87192 4.37372
+5.56859 5.90066
+-0.368163 1.4593
+5.44031 7.81671
+2.66342 2.99253
+6.11846 7.69499
+4.98811 5.17531
+4.45078 4.67513
+4.88206 4.94128
+2.51813 3.0268
+0.461292 1.15264
+2.34766 4.48652
+0.198819 2.23425
+6.85634 6.98248
+0.912438 1.81872
+4.84933 6.34912
+5.15613 5.82891
+0.172772 0.994083
+3.37381 3.64549
+1.98836 3.2697
+1.64344 2.06049
+0.766585 3.09305
+7.8979 8.28046
+4.34856 5.01341
+6.69809 7.24239
+5.19034 7.04959
+5.3747 6.92123
+7.8893 10.1251
+6.11207 6.99125
+5.37115 6.84111
+9.04786 9.11002
+6.45326 6.64415
+-0.76294 0.92832
+0.980411 1.8166
+3.05536 3.50031
+6.10827 7.55786
+6.57848 9.06264
+7.66855 8.861
+4.80276 4.82283
+1.99932 3.2877
+9.45229 9.80653
+0.457474 0.778684
+5.44444 5.95239
+5.60974 8.05169
+7.64656 7.79632
+6.78372 7.65134
+6.93878 7.82023
+9.08292 9.55308
+9.16329 9.25802
+1.4909 2.38688
+4.31881 5.3564
+5.12535 5.60119
+2.44591 2.54637
+7.36929 7.80452
+2.13707 2.97655
+9.73557 9.94588
+1.96637 3.36097
+0.857068 2.29643
+5.58224 5.91142
+8.90714 9.0255
+9.77988 10.0711
+0.41121 0.970955
+-0.518356 0.91447
+7.58725 7.71255
+8.1435 8.78712
+6.5487 7.17991
+4.94961 5.50283
+8.14086 9.03281
+3.51281 5.24806
+3.5786 3.84066
+6.27435 8.37735
+8.65263 9.5555
+2.87484 3.56117
+5.57707 6.55879
+-0.111276 0.264178
+3.60894 4.15477
+2.82322 3.64397
+8.40669 9.1127
+8.43089 10.5298
+1.38472 2.2453
+1.74464 2.00472
+4.01588 4.67572
+0.408869 0.938602
+2.06155 3.46067
+4.4871 5.08963
+2.4435 3.87355
+1.32864 2.55801
+4.78579 5.26122
+7.43027 7.57749
+6.90971 7.32716
+8.01095 9.46872
+9.41627 10.524
+8.83143 10.4474
+0.631816 1.75513
+1.72965 2.17123
+-0.513239 1.1886
+6.75616 6.7984
+2.49278 4.26493
+0.230011 0.966298
+3.78506 4.95013
+2.03886 3.14808
+7.87309 10.5637
+3.54564 3.58055
+1.91974 2.9194
+4.8503 4.98668
+4.66494 4.83558
+7.57916 8.24358
+4.78743 5.38547
+2.81034 3.34534
+1.00297 2.0138
+6.87593 7.17736
+3.93157 5.0655
+3.10361 4.05519
+8.22876 8.38326
+7.48377 8.31026
+2.23106 3.4905
+0.130934 0.606709
+1.22344 2.55898
+7.55829 7.92597
+4.10977 4.86263
+0.122756 0.264176
+3.8357 4.15854
+1.28414 2.13031
+0.280029 0.805504
+2.88245 4.1704
+5.57936 6.94781
+6.22719 6.33201
+-0.761013 1.16475
+6.16636 7.12566
+2.98935 3.192
+2.23263 2.34362
+3.9082 4.11692
+2.66865 3.5275
+1.87676 2.43966
+4.60035 5.39332
+2.74287 3.73097
+2.81953 3.96666
+5.73644 6.04042
+4.02179 4.52419
+3.26438 4.07346
+1.22509 2.13719
+7.91885 9.71846
+1.28152 1.48079
+7.97918 9.26344
+8.75682 9.8677
+7.25678 7.45362
+8.16161 8.87066
+1.21873 2.37224
+7.76739 9.06346
+3.89932 5.03406
+3.53901 4.37006
+2.93795 4.04333
+6.36543 6.72985
+4.72622 4.98804
+1.86205 1.99008
+0.784581 2.05264
+0.978519 2.91723
+3.9067 6.47195
+0.735425 2.38151
+8.37394 8.41609
+6.91804 7.23374
+9.39259 10.1026
+7.28732 7.43466
+4.75982 5.44264
+6.71504 7.53933
+2.17125 2.54358
+0.703562 1.39087
+-0.221711 0.541965
+9.22839 9.39159
+9.53465 9.97585
+1.44304 2.53666
+7.886 8.85051
+9.33174 10.1632
+2.60898 3.42889
+1.73658 2.02589
+6.31651 6.77762
+7.26755 8.34499
+9.01312 10.9837
+7.47361 8.96251
+7.98365 8.02586
+1.40065 3.44891
+9.44617 9.55391
+8.24265 9.34849
+9.366 10.4216
+0.375354 1.17522
+3.37114 3.38278
+-0.742469 1.07634
+4.29988 4.81879
+4.18605 7.21928
+7.41047 8.29198
+6.68173 7.60225
+3.24292 3.30695
+1.8951 3.42167
+3.97359 4.2857
+4.72621 5.80575
+4.75014 5.02239
+6.43454 6.94568
+7.16601 8.10355
+2.16685 2.23666
+6.70852 8.63284
+8.16988 8.95848
+0.277002 1.30648
+1.5803 2.28632
+2.22634 2.34679
+0.200623 0.814959
+5.27457 6.51651
+2.49533 2.90705
+6.48922 6.69528
+8.18879 8.63551
+2.75159 3.633
+0.884853 1.56434
+1.87488 3.98951
+4.24783 5.17713
+6.22499 6.56095
+5.68238 5.99272
+3.75553 3.85012
+4.87543 5.39966
+6.62671 8.72493
+3.50262 4.05131
+5.38952 5.4974
+7.84971 7.94051
+5.39123 6.66564
+5.43986 6.17256
+7.48968 7.7677
+4.2685 4.57296
+1.75169 4.11058
+5.03634 5.16102
+4.68003 4.84715
+8.36249 9.98761
+8.94297 10.6969
+6.21572 6.24305
+7.90303 8.0672
+7.90426 8.41244
+5.98512 7.93187
+5.13297 5.27136
+6.58367 7.4971
+4.72663 5.22956
+7.99667 8.59246
+4.3303 5.92188
+1.3132 1.80875
+7.70104 9.20947
+1.78862 2.00473
+9.63678 9.65571
+-0.264416 0.318054
+2.70004 3.40777
+2.74642 3.73608
+3.6494 3.6743
+8.03113 9.22851
+1.07526 1.3116
+4.05436 5.33291
+4.60907 6.03605
+7.83426 9.10358
+2.27997 2.77309
+5.63139 6.92616
+4.40717 5.25214
+1.98986 3.5062
+2.42393 2.9584
+1.94336 3.08456
+1.20185 3.01827
+0.641733 2.10095
+7.25046 8.29391
+0.640392 1.26451
+3.9588 4.85492
+6.83036 7.41101
+6.48581 7.08757
+6.48734 8.47856
+9.55084 10.3774
+-0.173137 1.26574
+2.32702 2.58775
+2.7463 3.13914
+7.86951 8.62807
+5.96916 7.92759
+0.217046 1.70373
+1.04207 1.05755
+4.79058 5.07902
+4.19024 5.35395
+9.00175 9.83715
+8.37554 9.275
+4.5204 4.82999
+3.49936 4.75519
+7.07916 7.74619
+6.66726 7.35282
+7.39513 8.55523
+7.50381 9.60708
+1.39304 2.26927
+2.84101 4.76376
+1.21779 1.59353
+4.7893 5.70143
+9.12195 9.57131
+5.40461 6.15443
+2.86445 4.26837
+8.01324 10.9082
+2.96659 3.8042
+2.4897 4.59323
+6.37887 7.15878
+7.00143 7.6419
+3.22491 3.41843
+1.22852 3.31783
+2.09881 2.56121
+4.43205 4.67051
+4.39328 4.66715
+2.38355 3.39058
+0.638802 1.59399
+5.32717 5.81376
+8.00353 9.72007
+8.77281 9.81649
+8.95552 9.86609
+2.90915 3.96556
+3.88176 4.93124
+6.45945 7.69942
+-0.108577 1.57424
+0.304992 0.320561
+6.47789 6.5515
+1.98211 2.05312
+6.2741 7.35626
+9.45057 9.67918
+5.2916 5.48037
+0.158802 0.712187
+6.42002 6.84323
+9.11085 9.13063
+9.42446 9.95882
+6.03624 6.96469
+9.2473 9.6286
+7.10342 8.71163
+3.34072 3.35187
+7.4602 8.58506
+8.7963 8.81873
+0.323615 2.22687
+0.326746 1.76681
+2.20062 2.76862
+7.55181 7.85006
+0.941035 1.28117
+8.76643 9.60019
+9.19731 9.33092
+6.0479 6.57293
+6.12725 6.24356
+7.53078 8.92488
+3.1841 3.48283
+1.85544 2.01888
+7.3849 9.29183
+5.03915 5.27721
+4.77142 5.46282
+-0.291696 1.14641
+1.61367 2.20867
+5.31853 6.69431
+2.52731 3.13139
+4.86677 5.18106
+4.50183 4.60969
+5.95881 6.09964
+2.41939 4.42026
+6.92003 7.17891
+4.29584 5.48557
+8.02803 9.06315
+2.82326 3.49599
+5.8647 5.87561
+2.38814 3.62688
+6.32418 7.17662
+5.99907 6.5059
+3.84698 4.14446
+9.80728 9.82132
+5.2366 6.30871
+9.81878 9.91004
+1.53024 1.83525
+2.98035 3.68531
+4.5418 6.98786
+5.19561 5.9846
+0.946068 1.46672
+3.26948 4.71928
+6.13476 7.68682
+8.36934 9.65072
+6.40074 7.14762
+1.01349 1.80493
+8.4514 10.25
+-0.180382 0.682704
+1.03041 1.63565
+5.64642 6.96069
+2.73598 3.67485
+5.8705 6.66157
+4.68343 4.7176
+5.83787 7.6818
+1.42529 2.234
+3.73726 4.19241
+5.38341 5.81884
+1.13088 1.69073
+0.968034 1.98828
+1.06007 1.11039
+3.50129 4.51807
+5.83133 6.77904
+-0.334945 1.29129
+0.326706 1.16015
+9.15028 10.4391
+5.13047 6.79712
+1.06952 1.38997
+5.79345 6.49898
+7.88149 8.5143
+8.00404 8.09794
+8.22725 8.28904
+6.38406 6.61356
+6.32166 6.73458
+7.17066 7.32049
+1.64338 3.79327
+7.92135 8.55568
+7.15578 7.42231
+6.70701 7.65427
+5.76608 7.63064
+3.54163 4.08662
+3.81402 6.76906
+4.5998 4.61865
+9.01471 9.18718
+5.21234 5.73335
+0.946018 1.39917
+6.99714 8.29739
+5.64458 6.93965
+3.39809 5.70907
+6.32284 6.83604
+8.50347 8.53097
+3.90118 4.85721
+9.41198 9.62076
+4.41514 5.55152
+7.69979 7.81249
+5.34434 5.37105
+7.25274 7.76114
+7.67383 7.92718
+5.82851 6.29417
+0.935651 1.2842
+0.639586 0.786771
+6.39823 8.31226
+3.67546 4.89035
+9.20323 9.57287
+2.33896 2.99576
+8.51933 8.80243
+0.983098 1.11084
+8.48215 9.42998
+7.29586 7.3914
+2.00695 2.89046
+2.60909 2.62433
+2.04118 2.92033
+7.60386 9.01419
+7.32896 7.73342
+9.51693 9.54891
+5.1323 5.24962
+6.35326 7.18302
+2.50952 3.51872
+3.4149 3.57431
+9.18412 10.4976
+5.68123 6.42697
+5.87758 6.0124
+6.3202 6.64588
+8.2547 9.98176
+5.50949 5.7854
+0.0824268 0.128178
+2.17292 3.76233
+7.22786 7.68214
+5.09326 6.4151
+4.30171 4.86688
+2.39206 3.47399
+7.95152 8.35556
+2.40133 2.936
+2.77819 3.87516
+3.252 4.33376
+9.54269 9.7513
+6.6747 6.73043
+0.611474 1.97158
+7.65864 8.53689
+1.58345 1.8017
+2.56917 2.8152
+8.5424 8.8301
+4.98159 5.44499
+5.82482 6.03578
+3.55509 4.90785
+5.77028 5.94747
+0.163965 1.1379
+2.85039 2.94261
+4.24343 4.67273
+3.22636 4.06084
+6.03662 6.21018
+4.55495 5.07697
+1.91173 2.51739
+6.54894 7.24036
+5.55502 6.92676
+0.245707 0.586188
+2.28044 3.29563
+4.71378 5.25198
+8.28953 8.44891
+9.42282 10.179
+5.0548 5.73614
+6.3203 6.43659
+6.54178 8.82077
+3.67181 4.17365
+8.51445 8.96445
+1.69648 2.84524
+0.194222 0.920147
+2.48533 2.59803
+1.66002 1.6739
+4.79833 4.95404
+1.09801 1.11009
+6.62529 7.4066
+8.0099 8.37262
+3.55429 4.11824
+6.2666 7.12137
+7.83222 8.01342
+9.37156 9.72961
+1.1647 4.04434
+4.50719 5.09068
+3.25175 3.75482
+8.28659 9.30848
+7.30009 8.60755
+-1.12073 1.21016
+0.310087 0.725712
+8.3746 9.13511
+9.11925 10.2234
+9.68703 9.7137
+0.603098 0.844291
+5.88373 6.99327
+0.852802 1.43297
+3.7463 5.82283
+7.69639 8.25446
+-0.337322 0.977113
+8.76606 9.16618
+3.43527 3.6616
+3.93587 5.39471
+5.66569 7.20462
+5.34999 5.7193
+3.25589 3.706
+1.52012 2.55985
+4.74228 5.43725
+5.15323 5.51652
+7.77237 8.33717
+-0.0514419 0.914127
+9.27182 9.59476
+8.14192 9.74859
+6.42702 7.20331
+7.51351 7.68358
+7.0947 7.46059
+7.97635 8.59449
+2.39931 2.66008
+5.79481 5.94673
+4.41054 4.81613
+2.72202 3.61239
+2.86039 3.44719
+1.81115 3.28151
+-0.566995 0.734214
+9.61998 9.72024
+7.4163 7.61821
+0.42522 0.552659
+3.17617 4.36942
+0.740294 1.36953
+7.13755 8.39966
+0.219186 0.892588
+3.78307 5.2905
+0.783026 1.76155
+3.01893 3.33055
+3.12143 3.5713
+-0.792679 0.92539
+0.668572 1.12961
+3.88619 4.30545
+7.59276 8.1776
+4.71509 5.05622
+6.53406 7.04242
+1.581 2.21984
+4.7144 5.51372
+2.76338 3.50211
+0.16364 0.293599
+5.92365 6.10636
+3.11174 4.29165
+5.49295 6.48717
+-0.503239 0.795707
+7.30558 8.12408
+2.10674 4.13456
+7.11985 8.01932
+1.34672 1.48739
+4.05778 5.69084
+2.83686 2.9115
+6.4471 6.53909
+0.467374 1.84371
+2.76467 2.94177
+4.87867 5.33932
+0.892878 1.96273
+1.13934 2.27205
+7.76918 8.39409
+6.72181 7.43901
+7.0836 8.68472
+7.12924 7.56332
+0.689172 1.62922
+9.41146 9.91043
+0.398265 1.27579
+6.29966 7.4874
+5.09438 5.65334
+6.04623 6.4687
+5.75305 6.89731
+0.308118 0.459501
+3.63692 4.30501
+3.1755 3.71009
+7.32787 7.52785
+2.23235 4.09978
+2.71191 2.91513
+0.209457 0.840713
+7.31489 7.38296
+6.21245 6.91111
+5.75983 5.96049
+5.92056 8.24518
+-0.354452 0.489638
+4.05894 5.34828
+1.56299 1.57414
+2.85083 3.27455
+8.78323 10.0012
+0.208502 1.26471
+6.10824 6.79285
+5.55114 8.03968
+6.13077 6.32342
+7.34865 7.82592
+3.94835 4.75016
+7.8268 8.72249
+4.85131 5.07903
+5.40398 6.0134
+2.85971 3.85293
+0.126379 1.45545
+3.15768 4.28388
+9.64566 9.70016
+4.47514 6.31064
+6.44995 7.2894
+4.70992 6.13777
+3.91128 4.22263
+7.35627 8.07739
+2.49215 2.68749
+8.09946 9.16929
+0.925679 1.92784
+8.48437 8.63892
+7.2255 9.18109
+-0.00840282 0.0168954
+5.91933 6.6274
+4.16086 4.64302
+8.27009 8.47868
+1.73372 2.93094
+8.17421 9.17705
+9.19136 9.43222
+0.0653594 0.648416
+8.69 8.96184
+8.99355 9.40832
+6.25088 6.26945
+6.72391 7.38424
+9.59708 10.3496
+6.00971 6.18818
+4.64468 5.75797
+3.64832 5.30079
+5.99378 7.8792
+6.5388 6.99379
+7.31694 8.43802
+3.66227 4.92638
+9.55964 10.3796
+-0.14433 0.29095
+3.56716 3.71252
+3.82062 4.27788
+8.10405 9.35275
+7.17891 7.46539
+1.17698 1.29602
+4.48829 5.03134
+7.18025 8.13852
+9.42388 10.3634
+5.2158 6.17469
+5.22926 6.52397
+5.16731 6.40625
+6.53348 7.269
+2.07834 2.39172
+9.65044 10.1519
+8.64551 10.1294
+9.29006 10.5993
+1.50639 2.83173
+5.71675 5.99216
+3.0783 3.35571
+0.115401 1.31431
+8.03988 8.11942
+3.11917 4.53956
+1.14552 1.1646
+5.34782 6.43017
+0.0701702 1.0368
+0.183335 0.440704
+6.33438 7.71607
+2.11533 2.64323
+7.12104 7.13366
+7.21548 8.26968
+3.13445 4.13568
+4.57452 4.74602
+2.60889 3.69846
+7.21184 7.47573
+6.87651 7.03405
+2.65431 3.94352
+1.50006 1.70087
+6.16344 7.54429
+7.02057 7.73067
+8.27833 9.01489
+0.500833 0.597845
+8.34751 9.88925
+2.80242 2.91837
+5.29424 6.079
+8.36276 9.10074
+0.216887 0.268335
+1.30798 3.16393
+3.93851 4.22658
+2.58028 3.14744
+9.31131 10.3451
+7.37262 8.84852
+4.45306 5.6723
+3.74535 4.0721
+4.90174 5.63875
+3.41847 4.65199
+3.10265 3.82548
+6.56126 6.97557
+2.57449 2.95098
+7.97418 9.06301
+9.2203 9.66829
+4.64922 4.96305
+8.83034 10.115
+6.6685 6.89847
+7.36585 7.48669
+8.66761 9.39287
+0.562216 0.961875
+7.56292 7.81006
+8.50715 8.95572
+0.572825 2.24755
+5.9367 6.06766
+-0.769578 0.776163
+4.48224 4.9553
+8.21069 9.29643
+8.57206 9.47175
+1.10032 1.21371
+3.76306 3.87152
+6.46197 8.18457
+6.96501 9.70727
+3.42357 3.93484
+0.818601 2.42743
+-0.119739 0.397938
+-0.378761 0.523892
+8.03394 9.35409
+3.60283 3.98864
+2.21789 2.70607
+-0.255329 0.319063
+6.20806 6.22609
+7.1283 8.04391
+3.73565 4.03638
+8.5374 9.10987
+5.22675 5.35072
+7.51777 7.58439
+9.12636 10.4159
+9.15003 9.40672
+0.217863 1.19883
+9.42416 9.9178
+2.55337 3.8088
+7.03655 7.98242
+9.17171 9.8047
+0.110162 0.722738
+3.16467 3.58897
+6.47244 7.12961
+1.0456 1.65614
+1.58456 1.62844
+1.79039 1.84035
+6.24286 7.07838
+9.08631 9.11684
+3.05068 3.40838
+2.81212 4.03665
+2.52011 3.09841
+8.06001 8.16356
+7.07649 7.52685
+2.47666 2.86548
+8.66241 8.95103
+-0.298116 0.662697
+0.822443 2.46125
+2.07619 2.33674
+4.84135 6.21034
+7.49625 8.13026
+7.85854 8.29618
+3.01722 3.37062
+6.54393 7.30306
+2.21113 2.30166
+8.32138 8.57349
+6.2995 6.33514
+3.0018 3.56886
+4.63378 5.52214
+6.71908 8.96715
+2.29809 2.95581
+8.34947 8.71096
+4.96902 5.32075
+9.51051 9.72733
+3.311 4.77789
+3.50233 3.66309
+4.95177 5.76002
+6.12876 7.22391
+6.27743 6.79393
+3.60638 3.6833
+5.20305 5.50848
+7.16065 8.88358
+9.45049 10.2539
+6.16892 7.0314
+8.08479 9.74516
+0.0717867 0.669987
+2.17569 3.34098
+4.81716 5.7509
+7.63999 8.01157
+5.87228 6.60363
+3.39621 4.35575
+4.96079 5.07901
+7.57639 8.82003
+8.27285 8.52609
+0.665858 1.64782
+1.74256 2.07126
+6.19512 6.4258
+0.664592 1.30896
+0.180682 1.43746
+6.46752 6.81303
+2.55562 3.08708
+9.33695 9.63312
+6.33821 6.77092
+7.88252 8.55026
+8.17937 8.45385
+-0.415294 0.793096
+5.22077 5.54553
+8.67808 9.10041
+1.72096 1.92024
+0.492778 1.48076
+2.29514 2.88531
+0.0934389 1.37614
+8.40297 9.11121
+3.66605 3.91717
+-0.274468 0.867811
+9.41428 9.56659
+1.22657 2.12792
+8.71336 9.85384
+5.09347 5.42905
+2.02877 2.36652
+5.99112 7.40703
+0.911618 3.48138
+4.84352 5.11131
+1.16309 2.08613
+5.58561 5.84805
+0.663543 1.08921
+1.83189 3.93269
+4.07731 4.38879
+4.04789 4.9989
+2.09457 3.61279
+2.00982 2.94396
+7.37537 7.66574
+5.08648 5.80122
+9.19959 10.2263
+4.26136 4.86194
+6.67875 7.61134
+1.27462 2.48399
+7.2237 7.82324
+-0.0141009 0.0441377
+8.32069 8.36192
+2.82562 3.0717
+-0.528918 1.25301
+1.90486 3.04714
+1.34489 1.75301
+3.14332 4.03322
+8.55351 10.8681
+9.09824 10.3828
+0.496868 0.622499
+7.11112 7.62765
+0.335233 0.528962
+6.71335 7.13937
+6.78574 7.71172
+9.13568 9.22251
+7.10299 7.64765
+3.64747 4.06685
+8.64041 9.40111
+2.43515 2.93081
+2.95476 3.68588
+0.0863751 0.777976
+6.5891 8.18165
+8.80986 10.0735
+0.568868 1.63785
+4.41677 5.42049
+8.72857 9.88426
+3.67467 4.25442
+8.98168 10.1087
+5.08611 5.50098
+1.28982 2.34422
+-0.914176 0.969847
+4.35042 4.42735
+4.02282 5.08164
+9.00566 9.4791
+2.71821 3.24065
+3.20252 3.24988
+8.61559 9.6733
+3.15157 4.7685
+3.59348 4.67872
+0.286864 0.36279
+8.40374 10.528
+7.53647 8.13523
+6.81591 6.90226
+7.68111 9.10704
+8.37958 8.73818
+3.25808 4.40893
+1.50348 3.00641
+0.20803 1.40949
+3.93771 4.84177
+2.79232 3.35329
+4.2666 4.63588
+0.341784 1.46241
+1.53063 2.06724
+8.58212 8.86194
+8.95411 9.70651
+8.71591 9.26292
+6.66088 6.7009
+3.95881 5.93917
+8.5823 8.76007
+-0.308958 0.34174
+1.03188 1.37677
+7.52675 9.84031
+4.27952 4.32984
+1.83465 2.27607
+8.12096 8.64922
+2.22605 4.40067
+0.00929139 0.871342
+0.376531 1.29354
+3.5257 4.30165
+1.95846 4.09589
+-0.200922 0.799272
+0.24432 1.76673
+4.73477 5.06514
+8.97059 9.2276
+2.89618 2.93969
+0.168256 1.03325
+3.44522 3.83622
+2.74889 2.76042
+6.07155 6.7979
+9.06484 9.09804
+7.56658 9.29215
+4.3084 5.45621
+-0.0786996 1.12809
+8.48249 9.74107
+6.4196 6.61469
+1.57119 1.87612
+3.15463 3.86251
+2.0089 2.57741
+6.53618 7.12035
+7.07901 7.29396
+0.114756 0.887413
+8.90806 9.65731
+4.0921 5.23407
+2.63441 2.92344
+4.31769 4.98832
+8.90336 9.26837
+8.25313 8.91204
+2.87758 4.00212
+-0.708243 0.789072
+3.28656 4.55872
+5.73177 5.80293
+5.40596 5.5844
+4.09318 4.57774
+6.16178 7.00613
+8.5514 10.5495
+6.83987 7.3056
+1.06341 1.97923
+7.82153 9.00722
+0.923069 1.42337
+1.83408 2.82331
+5.75305 7.23576
+0.241909 0.96721
+1.16645 2.10491
+5.41819 6.09839
+7.49242 7.69495
+0.347233 0.383681
+2.33245 2.53467
+4.91249 5.27759
+8.11182 9.2758
+0.0955456 0.548659
+-0.359909 0.48055
+1.64759 3.47097
+6.37855 7.40015
+0.423283 2.08857
+4.10068 4.46856
+2.58389 2.69626
+0.848483 2.72258
+8.67321 8.88903
+2.07607 3.42398
+3.11033 3.80741
+2.24735 3.48626
+8.11883 8.7687
+0.29959 1.41603
+4.84924 5.13641
+1.44102 1.74592
+1.13437 2.50296
+1.75876 3.09859
+4.75363 5.90838
+7.36423 8.20074
+5.51578 6.42652
+0.915633 1.86015
+9.44679 10.3479
+2.61691 3.60215
+6.26524 7.2538
+2.74326 3.12649
+5.83934 6.98592
+9.1111 10.4891
+2.27066 2.82709
+8.19359 8.67233
+0.834236 1.7066
+6.19288 7.21392
+-0.249843 0.891821
+2.5652 3.25132
+5.25356 5.88905
+3.99545 4.18918
+1.93186 2.51527
+4.44621 4.82421
+5.89181 7.36963
+2.77321 3.60627
+2.76444 3.88016
+2.50062 2.66105
+1.14846 1.66146
+2.951 4.81656
+3.81976 4.01061
+4.75674 5.59916
+6.74092 7.08289
+2.09989 2.32514
+0.220723 0.865303
+5.48107 5.71875
+1.48372 2.88941
+0.484577 1.12051
+8.93618 9.7185
+1.89769 3.65655
+2.0129 3.55214
+9.23173 10.3694
+0.286189 1.22753
+0.453785 1.55541
+2.24068 2.6541
+8.80917 10.4969
+7.12801 7.15222
+9.25745 9.9103
+5.73429 6.76901
+7.54454 8.47157
+1.96008 3.74997
+8.00837 9.25665
+1.66384 2.07613
+5.53014 5.97461
+-1.32495 1.33319
+4.58479 5.2263
+7.92048 8.75668
+6.87595 7.02522
+0.157713 0.389585
+7.48277 7.51261
+8.10714 8.38399
+0.0802723 0.587088
+1.13024 1.71135
+5.71769 6.84757
+3.08261 4.31054
+2.95952 5.09762
+6.62815 7.44256
+5.0805 5.8499
+3.38489 3.73265
+1.10644 2.18331
+4.70493 7.31686
+2.2253 2.6338
+0.778359 1.6265
+6.94211 7.2149
+4.20976 4.99342
+7.47792 7.67881
+7.06219 8.76137
+4.97677 6.12206
+6.30829 6.69361
+6.19977 6.76781
+9.67636 10.2172
+3.41958 3.69137
+0.374486 0.943711
+4.00837 4.80107
+8.85401 10.1325
+6.0938 7.8919
+1.51055 3.08998
+8.94594 10.3139
+1.06714 2.65511
+0.703202 0.850595
+4.87735 6.00659
+8.3067 8.39924
+7.78071 8.3155
+1.98737 2.81116
+6.86323 8.07974
+1.03479 1.34584
+0.490512 0.670211
+5.82122 6.1901
+5.50836 6.63385
+7.9192 8.9606
+0.913719 2.18983
+4.97151 5.70909
+4.19907 4.37712
+2.01188 2.63318
+7.84813 9.3771
+5.32667 7.48502
+8.50951 10.1006
+-0.551637 0.930509
+1.06511 2.23353
+1.91111 3.42663
+9.37528 9.55327
+7.27975 7.38741
+3.46676 4.83165
+7.36137 8.70333
+-0.295762 0.623228
+8.48558 8.81076
+2.71689 3.41873
+6.49265 8.11042
+5.25516 5.57336
+6.10462 7.05991
+8.76997 9.15164
+7.86196 8.30651
+7.82765 9.24604
+5.98573 6.34182
+6.45367 7.47857
+3.27018 5.10835
+1.3079 2.37423
+-0.261387 0.338113
+7.60683 8.81791
+4.7346 7.41988
+5.25597 5.28517
+3.76704 4.52226
+3.91774 6.66976
+5.69618 8.92667
+1.86148 3.07531
+5.57404 6.51438
+9.39049 9.77921
+2.38692 4.21416
+6.84909 7.23633
+7.2379 7.58761
+4.73485 6.11606
+7.80013 8.08105
+1.72701 3.40244
+2.44475 4.4072
+9.72565 9.77726
+3.35288 4.06493
+8.91215 9.92325
+8.67991 9.65865
+0.253195 0.764339
+4.23564 5.59497
+1.84752 2.14986
+-0.502957 0.528737
+1.32656 2.11347
+9.81563 10.0213
+7.60114 8.05035
+8.51797 8.83342
+-0.394604 1.41267
+7.71614 8.63514
+0.530249 0.968898
+2.90463 3.01675
+7.58098 8.71658
+-0.253747 1.28827
+1.832 2.39006
+7.2268 7.27225
+3.84076 4.66703
+2.2564 2.73185
+7.31508 8.46008
+4.99387 5.64948
+7.21239 7.79983
+7.60231 7.8473
+0.555482 1.41892
+1.25539 1.73665
+8.41561 8.96404
+5.06771 5.17664
+0.0655744 2.10718
+8.00222 8.65909
+7.48841 7.83609
+6.30909 6.89448
+9.1697 9.55942
+1.36259 2.22582
+-0.923854 0.994771
+3.43724 4.64053
+8.09411 8.19574
+4.84869 5.52805
+2.69802 3.4119
+9.0613 9.29405
+0.565216 0.687165
+5.93495 6.57426
+1.86925 2.75493
+1.41068 2.00824
+1.60612 1.62471
+3.11499 5.89909
+2.69806 3.90538
+3.76301 4.22135
+3.30065 4.70725
+5.56461 7.02137
+8.35335 8.99287
+4.79259 4.88508
+6.7911 7.52912
+8.14843 8.28583
+3.67629 5.06406
+5.71462 7.04747
+9.06721 9.99733
+4.87932 6.8586
+8.00814 9.57664
+7.03069 7.51623
+9.0989 9.57644
+2.70873 3.91296
+1.64425 1.7007
+6.53716 6.99033
+8.29874 8.74509
+1.88941 2.57626
+4.65337 5.23247
+9.04723 9.06665
+3.52258 3.61496
+1.1207 1.80143
+0.680601 1.98384
+2.94593 5.38692
+2.65685 2.67932
+9.00469 10.2054
+6.44318 7.2657
+4.66656 5.33893
+3.41719 4.72453
+3.12403 4.21748
+6.67973 6.81775
+3.54347 4.14978
+3.02554 3.50812
+3.91883 3.93657
+7.31721 7.89895
+1.86275 2.85473
+6.23266 6.4449
+7.59855 9.38013
+9.07084 9.49309
+0.557656 2.6851
+6.899 7.37693
+4.23162 5.84314
+8.54108 9.37672
+3.9513 4.79746
+7.299 8.29678
+5.58879 5.88551
+9.14992 9.22385
+9.1914 9.31788
+4.95663 5.56316
+2.16516 2.39538
+0.722262 1.89664
+7.76447 7.80026
+2.77772 3.39136
+9.59513 9.78635
+1.02728 1.2181
+7.32631 7.56611
+7.37389 7.46163
+6.87949 8.18689
+8.95602 9.81169
+5.85364 6.63434
+0.129136 2.13484
+7.09608 7.71167
+7.1487 8.34258
+7.48738 8.3172
+8.77247 9.95985
+7.6706 9.56828
+8.14268 8.61726
+6.5455 7.90871
+4.57866 4.78453
+3.63937 4.42349
+5.18905 5.36516
+4.68884 5.62995
+5.88338 7.83824
+-0.002979 0.145818
+4.42981 4.77141
+0.558593 1.07999
+6.91713 7.36159
+5.13948 6.20805
+3.34368 4.07112
+7.27365 7.8383
+9.6898 9.9514
+6.14332 6.75102
+2.16534 2.78843
+2.8007 4.37952
+7.67047 7.72955
+8.77377 9.85092
+1.26087 1.55193
+6.29788 6.58511
+7.68178 9.05777
+0.383336 1.21247
+2.55185 4.30874
+8.91971 9.21836
+3.67638 4.68596
+8.13843 9.13684
+-0.424353 1.97502
+2.71499 2.93977
+0.104447 0.387901
+4.09592 4.67009
+0.808593 0.920798
+5.01258 6.30662
+4.97668 6.57412
+8.44135 9.03816
+2.78932 3.72809
+6.71337 7.15128
+4.27234 4.50127
+6.78266 9.70351
+6.48026 7.51491
+7.36296 8.42283
+4.80339 7.3704
+6.24735 7.3132
+0.134626 0.364187
+2.73854 4.09422
+0.809997 1.19657
+6.41154 6.50244
+7.16847 8.56485
+1.53582 3.33985
+1.92874 2.86427
+6.95941 7.01378
+5.8592 6.54917
+2.51802 2.75622
+3.3894 3.6957
+2.2547 2.64693
+8.62054 9.1951
+8.86378 10.0003
+1.87892 2.28732
+3.83146 4.21484
+1.53262 1.99692
+7.86048 7.93125
+1.79437 2.68269
+3.92781 4.24119
+5.43044 5.47935
+0.322904 0.618854
+3.42383 5.18531
+4.00989 5.83612
+7.06304 8.76582
+5.88039 6.77654
+8.638 8.9479
+1.73391 2.09002
+1.04861 2.84779
+-0.313019 0.557659
+3.35245 4.1308
+9.05373 9.57205
+5.85684 6.49193
+6.00719 6.86421
+4.25244 4.65772
+5.15865 5.61529
+8.78498 9.77544
+8.33803 9.26452
+3.42915 4.92279
+8.29884 8.94035
+5.10232 5.35924
+4.33571 4.86695
+7.86184 7.90029
+7.34345 7.36214
+0.201624 0.800371
+9.05882 10.5503
+4.32188 5.03154
+-0.0456982 1.22298
+2.90921 3.60013
+1.69306 2.36564
+7.79029 9.15059
+4.65205 5.06538
+6.34552 8.32176
+7.92695 9.32585
+7.17903 8.09903
+9.53561 9.60287
+0.365723 1.23929
+0.542889 0.849053
+8.15061 8.93512
+6.40042 6.41053
+5.82666 6.5488
+1.00893 1.83717
+1.76021 2.11893
+7.61076 8.6242
+2.32513 3.4856
+4.39023 6.01094
+-0.11754 0.421848
+6.76371 6.94513
+4.67607 5.58732
+-0.201992 0.765553
+7.42926 7.44429
+2.57485 2.85339
+2.74138 4.13421
+8.21645 9.18107
+6.28184 6.4996
+7.129 7.74678
+7.76842 8.74924
+3.5359 4.35892
+3.04103 3.24376
+2.29389 2.92164
+6.96306 7.64415
+8.82053 9.04584
+1.19911 2.06167
+5.91357 7.6773
+0.150241 1.23291
+4.48681 5.41762
+6.89156 8.13443
+5.37828 5.79944
+2.13694 2.91102
+1.35932 2.08272
+6.14309 6.23278
+4.03202 5.88521
+7.23417 7.43704
+1.2501 2.60793
+2.12334 3.65727
+7.05722 8.77078
+0.437873 0.585933
+6.33338 9.16643
+2.44724 4.40234
+2.92012 3.64047
+1.2039 3.25195
+8.6611 10.0398
+8.0088 9.13622
+5.96562 7.08515
+5.45181 6.65246
+0.742546 2.38958
+4.12919 4.93571
+0.428823 0.84483
+1.45226 2.5869
+9.50727 10.0211
+7.69194 8.66273
+1.25706 2.44554
+5.23247 5.47762
+0.499178 1.70722
+7.26569 8.72467
+3.59815 5.50022
+1.03601 2.43445
+0.092414 0.927635
+3.7917 3.995
+6.21977 8.40398
+3.1513 3.81188
+9.80482 10.0951
+8.65564 9.33687
+2.06164 3.49152
+2.09754 2.34929
+0.66126 2.31888
+5.34832 6.82603
+7.91038 8.59105
+0.695523 0.800961
+2.33406 2.71629
+8.37774 10.9253
+9.7682 10.106
+9.44382 9.5743
+8.78009 9.47645
+1.87309 3.04127
+1.86724 2.13913
+3.30049 3.52416
+7.18508 7.6648
+1.3736 2.12153
+2.41879 5.06716
+1.87815 2.29743
+1.76646 2.06335
+9.73034 9.95475
+0.497489 0.686102
+6.96908 7.17338
+9.23111 10.0148
+3.30981 4.21787
+9.53311 10.3734
+-0.067709 0.147251
+8.44557 8.82047
+7.10407 7.47639
+0.834352 1.36908
+9.1598 10.6508
+4.22018 4.38279
+3.8295 3.95462
+3.97302 4.97247
+1.55856 2.31013
+0.0217962 0.486978
+1.69845 2.65786
+-0.489562 0.582187
+5.10621 5.6055
+9.8478 9.85919
+6.15389 6.92324
+7.11469 8.0418
+3.20625 3.78209
+5.93389 7.66892
+1.15134 1.18023
+6.84797 7.4239
+2.9483 3.22279
+-0.43205 0.764755
+7.17846 7.33313
+5.4729 8.26894
+6.19512 7.32132
+0.591934 0.767568
+0.49266 1.80691
+9.08272 9.72242
+5.85683 6.36905
+5.27625 7.13913
+3.60853 3.98155
+0.642811 1.10253
+1.27117 1.5329
+8.76096 9.61776
+4.9498 5.12847
+7.53282 7.80438
+1.40487 1.65657
+3.45329 3.84307
+3.25698 3.49614
+2.38651 2.89802
+8.23114 8.99016
+9.58516 10.4145
+5.5185 6.27733
+0.583068 0.892249
+1.93142 2.35084
+7.94845 9.22667
+2.47963 3.9005
+3.46106 3.86301
+7.77744 8.43735
+1.41072 1.73969
+9.12904 10.4307
+3.52227 3.66861
+5.4743 5.86487
+-0.51727 1.63657
+5.09861 7.03162
+5.14763 5.93411
+3.23526 3.47376
+0.9702 1.74063
+9.28366 10.3322
+1.80257 1.92265
+8.63597 9.08467
+4.16006 4.97753
+6.37418 6.39374
+5.82376 6.62429
+7.74751 8.68962
+1.63821 2.53399
+4.9864 6.40969
+0.680772 0.995608
+3.74344 3.83319
+0.898055 1.8593
+2.36839 2.39307
+7.21046 7.51006
+0.60893 2.91523
+3.15017 4.30412
+5.02219 6.28886
+4.60541 4.73379
+8.41196 8.58978
+8.84706 10.8198
+6.95807 7.54952
+5.54729 6.9315
+4.62574 4.73423
+3.35252 3.59865
+1.02207 1.71791
+3.16408 3.73993
+0.639222 1.69519
+7.57978 8.05813
+2.41371 2.77174
+8.65544 10.093
+6.31988 6.70758
+6.5301 8.39328
+0.578825 1.20331
+1.1243 2.07824
+5.86555 6.72397
+6.37103 6.81736
+1.12086 3.46541
+2.59503 3.44073
+5.27128 5.3616
+2.87331 3.4352
+5.48408 6.67916
+3.36016 4.09125
+0.813671 0.9811
+0.812162 3.22209
+6.85104 6.86306
+0.671311 0.979685
+2.75962 2.82659
+2.42186 2.49827
+7.82974 9.59669
+3.48851 3.60085
+8.47775 10.9574
+8.6863 10.6155
+0.196484 1.07469
+1.19293 1.45012
+5.79166 6.18466
+6.51597 6.6793
+9.78341 10.1992
+8.17879 9.59257
+6.96178 8.73165
+4.09161 4.31908
+3.19514 3.4072
+5.5101 6.32978
+0.188435 1.84481
+9.41738 10.0379
+1.46994 1.6294
+4.21915 5.39529
+5.46567 5.86638
+8.19414 9.201
+4.38616 4.55193
+2.31105 2.73345
+6.05897 6.12297
+8.84135 9.74232
+9.44943 10.2225
+3.27501 3.66059
+0.524904 1.74374
+7.7228 8.43799
+5.13274 5.82863
+8.2787 8.94491
+1.61463 2.03499
+7.04346 8.69977
+0.938308 2.38676
+0.00208037 0.0186158
+1.98744 2.05864
+7.05787 8.16211
+1.68383 2.04684
+2.24812 2.28257
+0.685061 1.2947
+2.25379 2.92827
+6.0052 6.24797
+7.06213 7.86344
+0.751849 2.96376
+0.0977921 0.513746
+8.43792 9.10545
+2.80769 3.09276
+9.19308 9.59741
+4.74365 4.99708
+8.41385 8.58422
+4.28093 5.9281
+4.26205 4.75417
+1.48035 1.61363
+1.4264 1.80922
+3.48365 4.52935
+1.78396 2.96351
+8.4134 8.96536
+8.65646 9.34781
+1.88027 2.97804
+8.92531 9.02743
+6.91815 7.88895
+5.68023 7.37521
+3.93105 4.6123
+0.385874 1.30785
+1.80151 2.24385
+8.43781 9.33927
+6.69643 8.001
+6.12062 6.673
+4.8316 6.63067
+9.00443 9.08204
+1.5651 2.65023
+3.57517 4.40231
+5.85127 8.02219
+8.02586 10.018
+2.00514 2.75138
+6.32104 7.84285
+8.90914 9.78319
+4.91325 6.27817
+3.87406 4.80327
+8.57887 9.30685
+1.40351 1.71079
+-0.217977 0.224497
+8.37711 9.56393
+5.54644 5.77714
+8.18206 8.36015
+0.774967 1.97899
+9.10434 10.1721
+9.39621 10.1135
+4.80108 4.90605
+9.45978 9.96227
+2.85412 4.05215
+5.71985 7.16735
+2.35081 2.82214
+9.34881 10.5899
+7.13014 7.82872
+4.54931 4.89725
+9.41397 9.9131
+8.90226 9.55276
+8.27995 9.83651
+9.2767 9.6053
+0.388751 1.40317
+5.01478 5.88869
+6.41521 7.21754
+1.22552 1.39067
+3.75771 3.81571
+4.39362 6.04592
+8.82639 8.84544
+4.59289 4.89208
+1.52235 1.64285
+1.85893 4.52056
+1.91781 2.78253
+3.34677 4.54987
+9.26905 10.6019
+7.10958 8.02083
+0.765257 1.66957
+2.17169 2.70214
+4.2293 6.38089
+1.41111 2.45992
+5.76864 6.85715
+2.19944 2.93182
+9.03727 9.6454
+3.82652 4.35225
+2.52642 3.09725
+7.77868 9.35844
+0.337665 1.00787
+1.92021 2.04418
+4.41862 5.95486
+9.47606 9.62386
+1.12113 1.55658
+5.26701 7.09712
+8.81478 9.34863
+6.29447 7.43847
+2.82379 3.57268
+7.9735 8.79936
+3.30176 5.50666
+6.36009 6.8864
+4.13583 5.00627
+0.510514 0.882245
+6.93864 7.78543
+2.04039 2.4298
+3.18337 3.19424
+4.20059 4.67088
+0.316687 0.707377
+0.169106 1.68194
+8.26665 10.2362
+1.1124 1.78306
+2.84603 3.33142
+9.48756 9.96651
+9.4301 9.7316
+0.234674 1.23981
+0.493232 0.522565
+1.342 1.41739
+2.57196 4.08221
+1.54201 2.52284
+5.32049 6.00052
+8.54218 8.59452
+-0.030524 1.64476
+2.31645 2.72528
+4.71898 4.92827
+0.0872997 1.74969
+0.994278 1.76964
+1.34411 2.77952
+0.156817 2.10245
+5.78094 6.34389
+3.09336 3.10563
+8.14245 9.0928
+9.34202 9.75484
+9.78415 10.0211
+4.68383 5.19384
+6.09441 7.90512
+6.74941 6.76118
+1.78693 1.91697
+2.34369 2.62141
+-0.20756 0.829082
+3.57681 5.11448
+2.44234 4.45153
+4.84521 5.31902
+1.80487 3.64498
+2.46125 3.02549
+-0.334514 0.64288
+8.06406 8.49886
+1.74559 2.54474
+6.05883 6.46529
+9.00014 10.2271
+8.00064 8.5061
+0.909467 0.980765
+8.65862 8.69736
+8.11457 8.77049
+3.93237 5.02485
+4.64507 5.34852
+3.92405 4.19449
+5.02381 5.21722
+3.76203 3.78396
+6.74925 7.34781
+8.2556 8.63585
+3.92521 3.99739
+1.44641 2.31509
+0.23516 0.917239
+4.4614 6.35489
+3.33221 3.95247
+1.73289 2.07919
+6.92385 7.55052
+8.74351 9.41125
+9.41451 10.1785
+7.4001 8.81081
+2.97038 3.12524
+7.26043 7.77569
+5.56625 5.59344
+5.70977 6.33362
+7.61443 8.43218
+1.05308 1.82947
+0.377602 1.57633
+6.42483 7.51505
+4.73011 5.43693
+7.72 8.09098
+9.20063 9.82287
+6.88273 7.35327
+6.88423 7.68356
+3.55293 3.6227
+0.947096 1.76021
+3.66411 5.67117
+9.31422 10.1035
+6.84847 6.98956
+2.16221 4.45806
+0.853284 3.15932
+2.48673 2.89793
+3.37633 3.90938
+1.6141 1.66363
+1.6658 3.01723
+0.419408 1.01736
+0.712239 0.791538
+2.25249 3.62425
+8.09772 10.2367
+1.46651 1.48148
+1.73233 2.0489
+7.42679 9.23232
+7.97446 9.53281
+2.74677 4.03955
+-0.169412 0.872795
+4.90663 5.40277
+7.62122 9.49334
+6.55971 7.34259
+3.71957 5.03775
+3.33226 4.06459
+0.634912 1.52603
+3.65506 4.09318
+4.31463 4.60534
+8.58287 9.85385
+0.334759 0.7232
+2.14027 2.866
+6.06611 6.3625
+2.53013 3.18764
+4.30913 4.89247
+6.53234 6.92328
+7.66419 8.61762
+1.37598 2.26754
+8.06279 8.80692
+5.28688 5.70608
+0.509396 1.34606
+8.80589 9.29765
+9.3801 10.3988
+0.402662 0.597735
+5.87213 6.63371
+2.79136 3.763
+6.20615 7.25189
+7.54065 9.62156
+4.12107 5.04454
+5.60294 6.69246
+1.20845 1.49272
+1.75679 2.56397
+2.83939 3.85147
+6.21362 6.71341
+9.01824 9.2388
+4.66617 5.04944
+1.48766 2.55674
+8.89442 9.42175
+5.29411 5.39531
+6.66271 8.68733
+0.730461 1.42466
+6.22927 6.55086
+0.566776 1.17299
+3.06104 4.17775
+5.28026 5.73966
+5.76071 7.61585
+7.83786 9.58106
+6.32199 6.46961
+8.89555 9.17429
+3.85772 4.97805
+6.63352 8.79211
+7.87234 7.94131
+6.53479 7.87979
+3.90293 4.50376
+6.21371 7.31788
+1.00497 1.75003
+6.90351 8.02435
+2.29142 3.9809
+6.26632 6.45283
+-0.0354471 1.31727
+8.80046 9.20169
+7.86905 8.36819
+0.848737 1.82393
+7.98136 9.40712
+3.97765 4.95399
+8.70252 9.26275
+3.13412 4.29389
+2.06446 3.55839
+7.67918 8.44509
+5.96082 6.40336
+1.20461 2.36924
+4.76741 5.74978
+9.41217 9.94305
+7.36736 8.07119
+3.44102 3.56957
+3.59893 4.52751
+4.2613 6.41628
+1.65321 3.02235
+3.70067 3.86657
+0.0176327 1.1215
+4.13592 4.88595
+8.73668 9.0834
+1.80944 2.95584
+6.05721 6.93009
+5.08206 5.38626
+1.86749 1.89392
+3.58284 4.10506
+0.0885586 1.47709
+5.46502 5.93066
+8.45338 8.47878
+3.46789 4.02317
+0.975506 1.15814
+7.12758 7.60073
+7.99582 8.56746
+3.11435 3.83805
+4.51166 4.52472
+8.39096 8.75934
+8.42208 9.66019
+2.48498 4.73703
+3.50301 4.81264
+6.40196 7.0733
+8.52138 8.82265
+1.49822 1.74634
+7.08547 7.93508
+3.47832 4.42948
+6.08646 6.20865
+4.46334 4.65278
+3.80008 4.08214
+3.4853 5.44308
+5.48109 6.18681
+6.59161 8.04307
+7.36554 7.38201
+5.2144 5.31725
+4.62607 7.25804
+1.24345 1.81263
+5.49248 8.16867
+6.4056 8.26316
+7.67828 8.56923
+2.46187 2.56974
+2.22942 3.27248
+7.14933 8.06682
+2.3236 2.95462
+4.18028 4.80535
+4.981 5.54215
+7.23261 7.34863
+4.96309 6.06396
+4.24402 4.44364
+0.917707 1.32687
+1.19806 1.65106
+3.7725 5.31412
+9.70021 9.84203
+5.99824 7.77474
+3.32636 3.84266
+8.59841 9.07653
+7.9916 9.14415
+0.786519 1.84655
+0.166394 1.47834
+2.87633 3.52808
+7.53804 9.56807
+6.14406 6.16189
+1.63428 3.96845
+1.10307 1.58897
+1.30032 2.85313
+7.89803 8.32723
+8.77593 8.90136
+1.68804 2.69447
+4.5956 4.6743
+7.39643 8.29839
+6.93629 7.82243
+6.10289 7.677
+1.83835 2.34295
+1.04506 1.91684
+8.95277 9.43817
+0.36153 0.643665
+1.02408 3.18963
+4.02972 4.40301
+2.80428 2.82552
+6.51718 6.64956
+0.185341 1.56607
+6.1658 7.59364
+4.09288 4.11687
+6.90205 7.16338
+5.0755 5.39478
+4.5614 4.83286
+5.8489 8.76295
+9.70079 10.0431
+8.44334 8.54714
+3.00139 3.66327
+5.34458 6.38895
+7.11481 7.96865
+4.66776 5.15678
+0.390138 0.53352
+2.01116 3.32839
+6.78761 6.97068
+4.57477 5.0724
+1.14098 1.36134
+7.4559 8.30327
+0.700932 2.40437
+1.90469 1.99046
+4.30064 5.11485
+7.84433 8.48543
+5.96212 7.49882
+3.93055 3.96317
+0.546327 1.04814
+8.96011 9.0404
+7.89255 8.06149
+0.669924 2.6944
+-0.00972314 0.837474
+6.07199 6.37467
+2.73659 3.19833
+5.9576 7.10966
+9.1316 9.14737
+5.26101 6.59184
+5.77697 8.08876
+0.68623 0.782805
+0.842619 1.39893
+5.82075 6.15957
+4.36394 4.88479
+7.1828 7.90107
+3.3331 4.39923
+6.54243 7.24966
+2.809 2.96491
+4.18514 4.61948
+4.95453 5.33929
+8.33288 9.52867
+9.05785 10.4276
+2.58917 4.74403
+1.34279 1.89014
+4.93626 5.75424
+7.75031 7.92788
+9.00904 9.02402
+3.91286 5.15124
+6.98486 7.34688
+-0.173169 0.415019
+0.652242 1.51556
+3.50184 5.30486
+3.72563 4.09022
+4.60463 6.58985
+3.34219 4.31833
+2.55445 2.58651
+6.14573 6.3669
+4.52336 6.37342
+9.37606 9.76836
+2.4198 3.36929
+2.89109 3.66974
+5.62463 6.05989
+0.674219 1.84165
+0.590017 1.71153
+1.54622 2.10277
+6.48003 6.55663
+3.56355 3.98573
+0.743671 1.87049
+3.27833 6.0722
+4.76267 6.9967
+2.80188 4.03037
+0.372694 0.482111
+5.73987 5.9529
+8.84732 9.49033
+0.833944 1.8157
+4.06126 4.36615
+0.884619 2.34622
+6.86723 6.99141
+8.07737 9.05193
+8.35903 9.00761
+8.84777 9.74001
+8.58058 9.05479
+8.28076 8.44566
+4.55155 5.65475
+2.44314 3.38966
+3.22172 4.50395
+7.1808 7.90376
+0.639636 1.72606
+5.46807 5.94322
+9.02146 9.87864
+-0.628472 0.655557
+4.29775 5.9553
+6.77525 7.38152
+6.51827 6.93542
+8.95252 9.52939
+0.755406 1.19973
+7.69455 7.86912
+0.170143 1.12949
+7.69254 8.08221
+2.08238 3.27051
+1.28662 1.78628
+1.21208 2.79391
+-0.155739 1.7071
+8.28833 9.10011
+5.77789 6.6954
+1.98395 2.35216
+5.77469 6.05177
+2.77565 5.81092
+-1.53416 2.30576
+6.93529 8.04506
+3.91553 4.55593
+5.57201 6.29071
+1.54149 1.86613
+4.09163 4.31234
+8.47834 11.1229
+5.70376 7.02981
+2.24683 3.79925
+5.4793 6.41036
+5.27644 6.81729
+0.13273 0.371437
+1.22959 1.41618
+0.551957 1.03276
+2.01269 2.4018
+8.77113 9.09395
+8.11753 8.46262
+0.39406 0.783705
+5.35964 5.48227
+7.24727 8.23233
+7.74525 8.85748
+0.0115736 0.882607
+1.78575 2.19684
+8.32514 9.0503
+3.11074 3.34975
+0.847464 2.13237
+0.310898 0.393528
+8.68841 10.518
+1.10032 1.83755
+2.42286 3.02554
+1.16364 2.80986
+1.46419 2.11421
+7.46021 7.90273
+6.86556 7.62542
+1.91466 3.79843
+3.1056 3.83969
+3.41591 4.26565
+0.285122 1.21372
+3.75441 5.52385
+1.07643 2.63403
+6.17341 7.67244
+9.13122 9.5132
+4.39696 6.15885
+3.7207 4.07729
+6.80782 7.1958
+6.65933 6.67105
+8.51535 8.7263
+5.98305 7.17759
+2.19609 2.46108
+8.21186 8.96908
+2.94729 3.60562
+3.31907 3.9297
+0.463492 0.626603
+2.62143 3.55089
+5.76898 6.79002
+1.45502 1.56525
+4.80797 5.62389
+5.87337 6.70588
+2.92765 3.50929
+0.412987 0.951057
+3.64594 4.40269
+-0.043401 0.502176
+4.54802 5.44613
+1.20218 1.8732
+2.75547 2.96745
+7.10348 7.7945
+9.74845 9.98835
+4.83718 6.4836
+2.30563 2.5903
+4.74016 6.30789
+6.42192 6.93329
+5.37294 6.73938
+2.4365 3.05787
+1.08283 3.79193
+4.90426 5.93563
+3.8874 4.83301
+0.13909 0.983027
+4.07407 5.61421
+8.62875 10.6851
+8.10233 8.29952
+2.23047 2.4691
+7.34617 7.39475
+1.66309 2.3032
+7.11207 10.0686
+4.52412 6.38666
+2.48323 2.96878
+7.47877 8.86547
+2.67607 4.33436
+6.83659 8.21075
+2.87313 3.39011
+2.81911 4.07729
+0.227877 0.657898
+6.57843 7.14311
+-0.591405 1.56925
+7.08018 7.59
+9.09558 9.3923
+9.48544 9.79474
+0.740233 2.33129
+8.51111 11.134
+7.79219 8.0281
+1.73821 1.89316
+9.21077 9.29488
+5.38354 6.46025
+4.30403 4.5472
+0.0893758 0.919238
+7.94464 8.51053
+5.27119 6.3741
+5.22476 6.00588
diff --git a/wasserstein/tests/data/test_5_A b/wasserstein/tests/data/test_5_A
new file mode 100644
index 0000000..51cff1c
--- /dev/null
+++ b/wasserstein/tests/data/test_5_A
@@ -0,0 +1,5 @@
+7.50638 7.78005
+0.991758 2.12178
+5.18481 6.61702
+6.14703 7.08581
+4.09936 4.83024
diff --git a/wasserstein/tests/data/test_5_A.pd.dipha b/wasserstein/tests/data/test_5_A.pd.dipha
new file mode 100644
index 0000000..be84441
--- /dev/null
+++ b/wasserstein/tests/data/test_5_A.pd.dipha
Binary files differ
diff --git a/wasserstein/tests/data/test_5_B b/wasserstein/tests/data/test_5_B
new file mode 100644
index 0000000..be62ed3
--- /dev/null
+++ b/wasserstein/tests/data/test_5_B
@@ -0,0 +1,5 @@
+5.8232 6.36308
+2.16066 2.48668
+2.38754 4.91418
+4.77403 5.43982
+0.291412 1.11147
diff --git a/wasserstein/tests/data/test_5_B.pd.dipha b/wasserstein/tests/data/test_5_B.pd.dipha
new file mode 100644
index 0000000..14ca67c
--- /dev/null
+++ b/wasserstein/tests/data/test_5_B.pd.dipha
Binary files differ
diff --git a/wasserstein/tests/data/test_diag1_A b/wasserstein/tests/data/test_diag1_A
new file mode 100644
index 0000000..f7f90ff
--- /dev/null
+++ b/wasserstein/tests/data/test_diag1_A
@@ -0,0 +1 @@
+1.0 1.0
diff --git a/wasserstein/tests/data/test_diag1_A.pd.dipha b/wasserstein/tests/data/test_diag1_A.pd.dipha
new file mode 100644
index 0000000..fa4a4d9
--- /dev/null
+++ b/wasserstein/tests/data/test_diag1_A.pd.dipha
Binary files differ
diff --git a/wasserstein/tests/data/test_diag1_B b/wasserstein/tests/data/test_diag1_B
new file mode 100644
index 0000000..a167a4f
--- /dev/null
+++ b/wasserstein/tests/data/test_diag1_B
@@ -0,0 +1 @@
+5.0 5.0
diff --git a/wasserstein/tests/data/test_diag1_B.pd.dipha b/wasserstein/tests/data/test_diag1_B.pd.dipha
new file mode 100644
index 0000000..621a55f
--- /dev/null
+++ b/wasserstein/tests/data/test_diag1_B.pd.dipha
Binary files differ
diff --git a/wasserstein/tests/data/test_diag2_A b/wasserstein/tests/data/test_diag2_A
new file mode 100644
index 0000000..a167a4f
--- /dev/null
+++ b/wasserstein/tests/data/test_diag2_A
@@ -0,0 +1 @@
+5.0 5.0
diff --git a/wasserstein/tests/data/test_diag2_A.pd.dipha b/wasserstein/tests/data/test_diag2_A.pd.dipha
new file mode 100644
index 0000000..621a55f
--- /dev/null
+++ b/wasserstein/tests/data/test_diag2_A.pd.dipha
Binary files differ
diff --git a/wasserstein/tests/data/test_diag2_B b/wasserstein/tests/data/test_diag2_B
new file mode 100644
index 0000000..a167a4f
--- /dev/null
+++ b/wasserstein/tests/data/test_diag2_B
@@ -0,0 +1 @@
+5.0 5.0
diff --git a/wasserstein/tests/data/test_diag2_B.pd.dipha b/wasserstein/tests/data/test_diag2_B.pd.dipha
new file mode 100644
index 0000000..621a55f
--- /dev/null
+++ b/wasserstein/tests/data/test_diag2_B.pd.dipha
Binary files differ
diff --git a/wasserstein/tests/data/test_diag3_A b/wasserstein/tests/data/test_diag3_A
new file mode 100644
index 0000000..151d4b1
--- /dev/null
+++ b/wasserstein/tests/data/test_diag3_A
@@ -0,0 +1,220 @@
+1.391781911475341 1.391781911475341
+1.395142124726278 1.395142124726278
+1.514181227875788 1.514181227875788
+1.528291566797427 1.528291566797427
+1.585389310674157 1.585389310674157
+1.629232116709072 1.629232116709072
+1.641428662445941 1.641428662445941
+1.646998748860116 1.646998748860116
+1.652915988616469 1.652915988616469
+1.69199679556404 1.69199679556404
+1.705727462482595 1.705727462482595
+1.706819293048617 1.706819293048617
+1.720175733750729 1.720175733750729
+1.728031840308488 1.728031840308488
+1.73797421040929 1.73797421040929
+1.739519744204842 1.739519744204842
+1.76132425248022 1.76132425248022
+1.767766952966369 1.767766952966369
+1.792444271021371 1.792444271021371
+1.831487552809192 1.831487552809192
+1.837086616049901 1.837086616049901
+1.851186504948943 1.851186504948943
+1.860502132730509 1.860502132730509
+1.8619433117852 1.8619433117852
+1.878229072834972 1.878229072834972
+1.880655074837347 1.880655074837347
+1.883647832802556 1.883647832802556
+1.884127769927503 1.884127769927503
+1.892969784466709 1.892969784466709
+1.916936460787894 1.916936460787894
+1.931545068229315 1.931545068229315
+1.937626522143119 1.937626522143119
+1.942267721488891 1.942267721488891
+1.963295334827521 1.963295334827521
+1.975655395743736 1.975655395743736
+1.981448090925679 1.981448090925679
+1.986220565173897 1.986220565173897
+1.98709020812351 1.98709020812351
+1.989420269013254 1.989420269013254
+2.007874648480185 2.007874648480185
+2.012179388983059 2.012179388983059
+2.019051972834053 2.019051972834053
+2.023278848058142 2.023278848058142
+2.026190677562545 2.026190677562545
+2.041594763633561 2.041594763633561
+2.042508934597344 2.042508934597344
+2.04305394648524 2.04305394648524
+2.052514683218775 2.052514683218775
+2.059038785694094 2.059038785694094
+2.062577320792516 2.062577320792516
+2.063488177732052 2.063488177732052
+2.067806664626417 2.067806664626417
+2.073013782498534 2.073013782498534
+2.08646120854976 2.08646120854976
+2.098476357223667 2.098476357223667
+2.101378199886176 2.101378199886176
+2.101927506425904 2.101927506425904
+2.12671744783454 2.12671744783454
+2.143966150630584 2.143966150630584
+2.145312642688415 2.145312642688415
+2.148704396208969 2.148704396208969
+2.153092682531471 2.153092682531471
+2.157553654759374 2.157553654759374
+2.176659075756566 2.176659075756566
+2.177260578806816 2.177260578806816
+2.179141269427014 2.179141269427014
+2.201895416482074 2.201895416482074
+2.202563945779844 2.202563945779844
+2.205113735193028 2.205113735193028
+2.207345865351049 2.207345865351049
+2.208922099676958 2.208922099676958
+2.218057898922937 2.218057898922937
+2.228610453267036 2.228610453267036
+2.241314066596301 2.241314066596301
+2.242145210071643 2.242145210071643
+2.253976266568437 2.253976266568437
+2.255324860119305 2.255324860119305
+2.271300972641221 2.271300972641221
+2.279438361991067 2.279438361991067
+2.286592331830957 2.286592331830957
+2.287159411646074 2.287159411646074
+2.296653147995115 2.296653147995115
+2.301754785182811 2.301754785182811
+2.30409930499031 2.30409930499031
+2.32141477565108 2.32141477565108
+2.347789281926012 2.347789281926012
+2.347827987256373 2.347827987256373
+2.349391321950732 2.349391321950732
+2.350129292983257 2.350129292983257
+2.358679083392328 2.358679083392328
+2.372845273125388 2.372845273125388
+2.385040766846267 2.385040766846267
+2.42114588843816 2.42114588843816
+2.425116524931602 2.425116524931602
+2.426518521893022 2.426518521893022
+2.43211651886311 2.43211651886311
+2.441302771998711 2.441302771998711
+2.446429340510857 2.446429340510857
+2.446547553904861 2.446547553904861
+2.45764765793376 2.45764765793376
+2.461222149682938 2.461222149682938
+2.467900747394114 2.467900747394114
+2.473214152160872 2.473214152160872
+2.5 2.5
+2.503557913626332 2.503557913626332
+2.504315621146863 2.504315621146863
+2.515634290122204 2.515634290122204
+2.516231935083851 2.516231935083851
+2.517558892374071 2.517558892374071
+2.526325773757754 2.526325773757754
+2.531164001388939 2.531164001388939
+2.53128061055404 2.53128061055404
+2.539387277827314 2.539387277827314
+2.540864599180268 2.540864599180268
+2.548084457784768 2.548084457784768
+2.548923292215475 2.548923292215475
+2.551730202825644 2.551730202825644
+2.553178578801818 2.553178578801818
+2.560295747947446 2.560295747947446
+2.566321603108612 2.566321603108612
+2.568932286976676 2.568932286976676
+2.574887688783916 2.574887688783916
+2.581809142325336 2.581809142325336
+2.584541960262555 2.584541960262555
+2.585511915815223 2.585511915815223
+2.592970592044868 2.592970592044868
+2.596055336381078 2.596055336381078
+2.598560573626668 2.598560573626668
+2.614019084614256 2.614019084614256
+2.618463725327216 2.618463725327216
+2.622883674481145 2.622883674481145
+2.627791161528314 2.627791161528314
+2.63535653879261 2.63535653879261
+2.654825898255443 2.654825898255443
+2.660423271276714 2.660423271276714
+2.667148030102869 2.667148030102869
+2.67012591760915 2.67012591760915
+2.698712599567882 2.698712599567882
+2.72180967799905 2.72180967799905
+2.732466204434637 2.732466204434637
+2.734187392905275 2.734187392905275
+2.737296308103857 2.737296308103857
+2.745724923243991 2.745724923243991
+2.749541709159369 2.749541709159369
+2.752925621447035 2.752925621447035
+2.754183973113479 2.754183973113479
+2.763972022430258 2.763972022430258
+2.766941997926879 2.766941997926879
+2.773850925522978 2.773850925522978
+2.777506755238121 2.777506755238121
+2.780333194223143 2.780333194223143
+2.783060349483276 2.783060349483276
+2.78679029681548 2.78679029681548
+2.786792895521339 2.786792895521339
+2.795170825459034 2.795170825459034
+2.801104989227437 2.801104989227437
+2.80525433080833 2.80525433080833
+2.805376738133109 2.805376738133109
+2.806844454092663 2.806844454092663
+2.811611818684648 2.811611818684648
+2.811994908451803 2.811994908451803
+2.816002798930236 2.816002798930236
+2.816814002472584 2.816814002472584
+2.818569391261086 2.818569391261086
+2.821660827076439 2.821660827076439
+2.822317588351085 2.822317588351085
+2.824910409962511 2.824910409962511
+2.829322097471409 2.829322097471409
+2.833852169620359 2.833852169620359
+2.839287537694811 2.839287537694811
+2.841714730677953 2.841714730677953
+2.841715058318205 2.841715058318205
+2.851653306950001 2.851653306950001
+2.853639002902003 2.853639002902003
+2.85515962291442 2.85515962291442
+2.855333736885793 2.855333736885793
+2.872540314564304 2.872540314564304
+2.879449214478037 2.879449214478037
+2.881003856158217 2.881003856158217
+2.881074731438092 2.881074731438092
+2.893589165559115 2.893589165559115
+2.898664743213686 2.898664743213686
+2.90387832180792 2.90387832180792
+2.919095859678745 2.919095859678745
+2.924945175440496 2.924945175440496
+2.931795145696962 2.931795145696962
+2.932285006979528 2.932285006979528
+2.934606807227626 2.934606807227626
+2.936392671567475 2.936392671567475
+2.953794710898493 2.953794710898493
+2.958055395706548 2.958055395706548
+2.960407744013656 2.960407744013656
+2.960759715914242 2.960759715914242
+2.969702548922556 2.969702548922556
+2.970149844982665 2.970149844982665
+2.978953970679893 2.978953970679893
+2.979075864664287 2.979075864664287
+2.984665519558418 2.984665519558418
+3.04548240149063 3.04548240149063
+3.050688336416719 3.050688336416719
+3.05773927378742 3.05773927378742
+3.059596740753369 3.059596740753369
+3.059762479996741 3.059762479996741
+3.088543279751235 3.088543279751235
+3.093580813520995 3.093580813520995
+3.104787362108069 3.104787362108069
+3.173380191779681 3.173380191779681
+3.583124637167399 3.583124637167399
+3.630658112409034 3.630658112409034
+3.631421639368965 3.631421639368965
+3.751087101339956 3.751087101339956
+3.800845709568037 3.800845709568037
+3.846558940956666 3.846558940956666
+4 4
+4 4
+4.076238038291317 4.076238038291317
+4.455547086147983 4.455547086147983
+5.356087357608394 5.356087357608394
+5.54364842773721 5.54364842773721
+7.587654388717225 7.587654388717225
diff --git a/wasserstein/tests/data/test_diag3_A.pd.dipha b/wasserstein/tests/data/test_diag3_A.pd.dipha
new file mode 100644
index 0000000..0dbfb89
--- /dev/null
+++ b/wasserstein/tests/data/test_diag3_A.pd.dipha
Binary files differ
diff --git a/wasserstein/tests/data/test_diag3_B b/wasserstein/tests/data/test_diag3_B
new file mode 100644
index 0000000..bb8655a
--- /dev/null
+++ b/wasserstein/tests/data/test_diag3_B
@@ -0,0 +1,193 @@
+1.167089173446239 1.167089173446239
+1.256234452640111 1.256234452640111
+1.303693422257498 1.303693422257498
+1.413255970488646 1.413255970488646
+1.697910382446573 1.697910382446573
+1.718844728805093 1.718844728805093
+1.734124820632724 1.734124820632724
+1.749572938304276 1.749572938304276
+1.770320424526358 1.770320424526358
+1.786344763036807 1.786344763036807
+1.810054737907635 1.810054737907635
+1.815127306170105 1.815127306170105
+1.837806648681218 1.837806648681218
+1.870552189043019 1.870552189043019
+1.897240351979503 1.897240351979503
+1.935562152643027 1.935562152643027
+1.952562418976663 1.952562418976663
+1.959552126104175 1.959552126104175
+1.979899732318601 1.979899732318601
+2.00044500769347 2.00044500769347
+2.028951227523087 2.028951227523087
+2.037678749316724 2.037678749316724
+2.047911420446857 2.047911420446857
+2.075181804515723 2.075181804515723
+2.077245386452578 2.077245386452578
+2.084751316684838 2.084751316684838
+2.084860886126203 2.084860886126203
+2.103286477421968 2.103286477421968
+2.106856827309345 2.106856827309345
+2.113139266068691 2.113139266068691
+2.114594962503455 2.114594962503455
+2.115917727493158 2.115917727493158
+2.122335878797089 2.122335878797089
+2.127359082726206 2.127359082726206
+2.131673381033273 2.131673381033273
+2.155015793320908 2.155015793320908
+2.162480684365264 2.162480684365264
+2.195207236194009 2.195207236194009
+2.203279931784429 2.203279931784429
+2.205567995563669 2.205567995563669
+2.212933962936773 2.212933962936773
+2.215081271089993 2.215081271089993
+2.225989037578865 2.225989037578865
+2.24218929203347 2.24218929203347
+2.246321319993257 2.246321319993257
+2.280059407166517 2.280059407166517
+2.284117669032543 2.284117669032543
+2.293233992770926 2.293233992770926
+2.298815356955373 2.298815356955373
+2.300542634724628 2.300542634724628
+2.326408290042679 2.326408290042679
+2.328797162040625 2.328797162040625
+2.36025798094028 2.36025798094028
+2.365031313604634 2.365031313604634
+2.372266311053883 2.372266311053883
+2.400053902049271 2.400053902049271
+2.409134054334209 2.409134054334209
+2.411368235895246 2.411368235895246
+2.415934766378347 2.415934766378347
+2.420989857074179 2.420989857074179
+2.422520269961376 2.422520269961376
+2.43377629944218 2.43377629944218
+2.449308615746858 2.449308615746858
+2.452936540056068 2.452936540056068
+2.453698388060092 2.453698388060092
+2.454711357943602 2.454711357943602
+2.459202673400056 2.459202673400056
+2.493778305287384 2.493778305287384
+2.537394117473177 2.537394117473177
+2.544674753106669 2.544674753106669
+2.558904304820755 2.558904304820755
+2.563089994365716 2.563089994365716
+2.565476194422898 2.565476194422898
+2.599756049189921 2.599756049189921
+2.603619661709009 2.603619661709009
+2.609775379385211 2.609775379385211
+2.622552038976658 2.622552038976658
+2.623798471910885 2.623798471910885
+2.635711198661633 2.635711198661633
+2.644229304223612 2.644229304223612
+2.661919064427223 2.661919064427223
+2.666783921498494 2.666783921498494
+2.675503310152301 2.675503310152301
+2.684228699964661 2.684228699964661
+2.696854617267681 2.696854617267681
+2.700538654666735 2.700538654666735
+2.744886611436907 2.744886611436907
+2.748618547996708 2.748618547996708
+2.757981496641135 2.757981496641135
+2.774766825791652 2.774766825791652
+2.784491736143893 2.784491736143893
+2.796482184304273 2.796482184304273
+2.800849254751463 2.800849254751463
+2.816963410000067 2.816963410000067
+2.825207379914743 2.825207379914743
+2.831286409028398 2.831286409028398
+2.844827082550712 2.844827082550712
+2.853558438121966 2.853558438121966
+2.859806035663089 2.859806035663089
+2.878956033959891 2.878956033959891
+2.886422825109222 2.886422825109222
+2.891566924618832 2.891566924618832
+2.892028419188578 2.892028419188578
+2.893138900330932 2.893138900330932
+2.894250936382814 2.894250936382814
+2.90112201577666 2.90112201577666
+2.902172795370005 2.902172795370005
+2.90967533504119 2.90967533504119
+2.919687125962211 2.919687125962211
+2.923711238894001 2.923711238894001
+2.929041907338841 2.929041907338841
+2.938734873084349 2.938734873084349
+2.939642428979572 2.939642428979572
+2.943010909640486 2.943010909640486
+2.944210926048103 2.944210926048103
+2.951091358234723 2.951091358234723
+2.953950275008233 2.953950275008233
+2.966943157369611 2.966943157369611
+2.982522008227535 2.982522008227535
+2.992174049247434 2.992174049247434
+2.993098995839607 2.993098995839607
+2.995311055519335 2.995311055519335
+2.996708164866609 2.996708164866609
+2.999922110096644 2.999922110096644
+3 3
+3.000364533251431 3.000364533251431
+3.003840990677832 3.003840990677832
+3.006672301312824 3.006672301312824
+3.016489409140306 3.016489409140306
+3.021123787004333 3.021123787004333
+3.039117818612596 3.039117818612596
+3.039555193616473 3.039555193616473
+3.049952247267922 3.049952247267922
+3.057673482371216 3.057673482371216
+3.06920083507411 3.06920083507411
+3.075505231082782 3.075505231082782
+3.079038628197304 3.079038628197304
+3.084265889701239 3.084265889701239
+3.086837468106297 3.086837468106297
+3.103873984398081 3.103873984398081
+3.11528125482979 3.11528125482979
+3.119720021802376 3.119720021802376
+3.132543753577128 3.132543753577128
+3.141822873359038 3.141822873359038
+3.143502053175705 3.143502053175705
+3.153232877003746 3.153232877003746
+3.157586960809866 3.157586960809866
+3.157966892275408 3.157966892275408
+3.163583225161638 3.163583225161638
+3.178188125342772 3.178188125342772
+3.178475867931057 3.178475867931057
+3.179372297765929 3.179372297765929
+3.186437137237586 3.186437137237586
+3.188053957464282 3.188053957464282
+3.199351610026191 3.199351610026191
+3.204566427513051 3.204566427513051
+3.22885278850648 3.22885278850648
+3.229088648916556 3.229088648916556
+3.236685523936269 3.236685523936269
+3.239854786600373 3.239854786600373
+3.255809161351669 3.255809161351669
+3.287718056143732 3.287718056143732
+3.294038308299402 3.294038308299402
+3.313688277153076 3.313688277153076
+3.325783245946608 3.325783245946608
+3.331072954808429 3.331072954808429
+3.354962852285211 3.354962852285211
+3.357502741262644 3.357502741262644
+3.373668509804576 3.373668509804576
+3.408653045775418 3.408653045775418
+3.416281541503763 3.416281541503763
+3.443144279972986 3.443144279972986
+3.492970564191033 3.492970564191033
+3.493767805580122 3.493767805580122
+3.559084134799019 3.559084134799019
+3.559898699300211 3.559898699300211
+3.833585501974904 3.833585501974904
+4.099502076836052 4.099502076836052
+4.484082147277348 4.484082147277348
+4.505718324707756 4.505718324707756
+4.891723119528026 4.891723119528026
+5.065300494905414 5.065300494905414
+5.188599238535201 5.188599238535201
+5.36134479630535 5.36134479630535
+5.609786508140671 5.609786508140671
+7.08640314680382 7.08640314680382
+7.113765883549079 7.113765883549079
+7.328944131981744 7.328944131981744
+7.63625182217108 7.63625182217108
+7.716743341311718 7.716743341311718
+7.938093404092351 7.938093404092351
+8.112783377863046 8.112783377863046
+8.131485096731454 8.131485096731454
diff --git a/wasserstein/tests/data/test_diag3_B.pd.dipha b/wasserstein/tests/data/test_diag3_B.pd.dipha
new file mode 100644
index 0000000..3fbfd90
--- /dev/null
+++ b/wasserstein/tests/data/test_diag3_B.pd.dipha
Binary files differ
diff --git a/wasserstein/tests/data/test_list.txt b/wasserstein/tests/data/test_list.txt
new file mode 100644
index 0000000..27340d8
--- /dev/null
+++ b/wasserstein/tests/data/test_list.txt
@@ -0,0 +1,21 @@
+test_5_A test_5_B 1.0 -1.0 4.320655
+test_5_A test_5_B 2.0 -1.0 1.7323016335246
+test_5_A test_5_B 3.0 -1.0 1.396199948
+test_5_A test_5_B 1.0 1.0 6.603006
+test_5_A test_5_B 2.0 1.0 2.73426775794691
+test_5_A test_5_B 3.0 1.0 2.13072755216204
+test_5_A test_5_B 1.0 2.0 5.1888795679967
+test_5_A test_5_B 2.0 2.0 2.26649677575857
+test_5_A test_5_B 3.0 2.0 1.86434961396614
+test_100_A test_100_B 1.0 -1.0 27.5573259
+test_100_A test_100_B 2.0 -1.0 3.38004972483238
+test_100_A test_100_B 3.0 -1.0 1.9045814702967
+test_100_A test_100_B 1.0 1.0 40.4375855
+test_100_A test_100_B 2.0 1.0 4.75252460986668
+test_100_A test_100_B 3.0 1.0 2.556594741819
+test_100_A test_100_B 1.0 2.0 31.7187555735287
+test_100_A test_100_B 2.0 2.0 3.81132239777023
+test_100_A test_100_B 3.0 2.0 2.09695346034248
+test_diag1_A test_diag1_B 1.0 -1.0 0.0
+test_diag2_A test_diag2_B 1.0 -1.0 0.0
+test_diag3_A test_diag3_B 1.0 -1.0 0.0
diff --git a/wasserstein/tests/test_hera_wasserstein.cpp b/wasserstein/tests/test_hera_wasserstein.cpp
new file mode 100644
index 0000000..0a80d2f
--- /dev/null
+++ b/wasserstein/tests/test_hera_wasserstein.cpp
@@ -0,0 +1,532 @@
+#define LOG_AUCTION
+#include "catch/catch.hpp"
+
+#include <sstream>
+#include <iostream>
+
+
+#undef LOG_AUCTION
+
+#include "wasserstein.h"
+#include "tests_reader.h"
+
+using namespace hera_test;
+
+using PairVector = std::vector<std::pair<double, double>>;
+
+
+TEST_CASE("simple cases", "wasserstein_dist")
+{
+ PairVector diagram_A, diagram_B;
+ hera::AuctionParams<double> params;
+ params.wasserstein_power = 1.0;
+ params.delta = 0.01;
+ params.internal_p = hera::get_infinity<double>();
+ params.initial_epsilon = 0.0;
+ params.epsilon_common_ratio = 0.0;
+ params.max_num_phases = 30;
+ params.gamma_threshold = 0.0;
+ params.max_bids_per_round = 0; // use Jacobi
+
+ SECTION("trivial: two empty diagrams") {
+ REQUIRE( 0.0 == hera::wasserstein_dist<>(diagram_A, diagram_B, params));
+ }
+
+ SECTION("trivial: one empty diagram, one single-point diagram") {
+
+ diagram_A.emplace_back(1.0, 2.0);
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ REQUIRE( fabs(d1 - 0.5) <= 0.00000000001 );
+
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ REQUIRE( fabs(d2 - 0.5) <= 0.00000000001 );
+
+ params.internal_p = 2.0;
+ double corr_answer = 1.0 / std::sqrt(2.0);
+ double d3 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ REQUIRE( fabs(d3 - corr_answer) <= 0.00000000001 );
+
+ }
+
+ SECTION("trivial: two single-point diagrams-1") {
+
+ diagram_A.emplace_back(10.0, 20.0); // (5, 5)
+ diagram_B.emplace_back(13.0, 19.0); // (3, 3)
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ REQUIRE( fabs(d1 - d2) <= 0.00000000001 );
+ REQUIRE( fabs(d1 - 3.0) <= 0.00000000001 );
+
+ params.wasserstein_power = 2.0;
+ double d3 = hera::wasserstein_cost<>(diagram_A, diagram_B, params);
+ double d4 = hera::wasserstein_cost<>(diagram_B, diagram_A, params);
+ REQUIRE( fabs(d3 - d4) <= 0.00000000001 );
+ REQUIRE( fabs(d4 - 9.0) <= 0.00000000001 );
+
+ params.wasserstein_power = 1.0;
+ params.internal_p = 1.0;
+ double d5 = hera::wasserstein_cost<>(diagram_A, diagram_B, params);
+ double d6 = hera::wasserstein_cost<>(diagram_B, diagram_A, params);
+ REQUIRE( fabs(d5 - d6) <= 0.00000000001 );
+ REQUIRE( fabs(d5 - 4.0) <= 0.00000000001 );
+
+ params.internal_p = 2.0;
+ double d7 = hera::wasserstein_cost<>(diagram_A, diagram_B, params);
+ double d8 = hera::wasserstein_cost<>(diagram_B, diagram_A, params);
+ REQUIRE( fabs(d7 - d8) <= 0.00000000001 );
+ REQUIRE( fabs(d7 - std::sqrt(10.0)) <= 0.00000000001 );
+
+ }
+
+ SECTION("trivial: two single-point diagrams-2") {
+
+ diagram_A.emplace_back(10.0, 20.0); // (5, 5)
+ diagram_B.emplace_back(130.0, 138.0); // (4, 4)
+
+ double d1 = hera::wasserstein_cost<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_cost<>(diagram_B, diagram_A, params);
+ REQUIRE( fabs(d1 - d2) <= 0.00000000001 );
+ REQUIRE( fabs(d1 - 9.0) <= 0.00000000001 );
+
+ params.wasserstein_power = 2.0;
+ double d3 = hera::wasserstein_cost<>(diagram_A, diagram_B, params);
+ double d4 = hera::wasserstein_cost<>(diagram_B, diagram_A, params);
+ REQUIRE( fabs(d3 - d4) <= 0.00000000001 );
+ REQUIRE( fabs(d4 - 41.0) <= 0.00000000001 ); // 5^2 + 4^2
+
+ params.wasserstein_power = 1.0;
+ params.internal_p = 1.0;
+ double d5 = hera::wasserstein_cost<>(diagram_A, diagram_B, params);
+ double d6 = hera::wasserstein_cost<>(diagram_B, diagram_A, params);
+ REQUIRE( fabs(d5 - d6) <= 0.00000000001 );
+ REQUIRE( fabs(d5 - 18.0) <= 0.00000000001 ); // 5 + 5 + 4 + 4
+
+ params.internal_p = 2.0;
+ double d7 = hera::wasserstein_cost<>(diagram_A, diagram_B, params);
+ double d8 = hera::wasserstein_cost<>(diagram_B, diagram_A, params);
+ REQUIRE( fabs(d7 - d8) <= 0.00000000001 );
+ REQUIRE( fabs(d7 - 9 * std::sqrt(2.0)) <= 0.00000000001 ); // sqrt(5^2 + 5^2) + sqrt(4^2 + 4^2) = 9 sqrt(2)
+
+ }
+
+}
+
+
+
+TEST_CASE("file cases", "wasserstein_dist")
+{
+ PairVector diagram_A, diagram_B;
+ hera::AuctionParams<double> params;
+ params.wasserstein_power = 1.0;
+ params.delta = 0.01;
+ params.internal_p = hera::get_infinity<double>();
+ params.initial_epsilon = 0.0;
+ params.epsilon_common_ratio = 0.0;
+ params.max_num_phases = 30;
+ params.gamma_threshold = 0.0;
+ params.max_bids_per_round = 1; // use Jacobi
+
+
+ SECTION("from file:") {
+ const char* file_name = "../tests/data/test_list.txt";
+ std::ifstream f;
+ f.open(file_name);
+ std::vector<TestFromFileCase> test_params;
+ std::string s;
+ while (std::getline(f, s)) {
+ test_params.emplace_back(s);
+ }
+
+ for(const auto& ts : test_params) {
+ params.wasserstein_power = ts.q;
+ params.internal_p = ts.internal_p;
+ bool read_file_A = hera::read_diagram_point_set<double, PairVector>(ts.file_1, diagram_A);
+ bool read_file_B = hera::read_diagram_point_set<double, PairVector>(ts.file_2, diagram_B);
+ REQUIRE( read_file_A );
+ REQUIRE( read_file_B );
+ double hera_answer = hera::wasserstein_dist(diagram_A, diagram_B, params);
+ REQUIRE( fabs(hera_answer - ts.answer) <= 0.01 * hera_answer );
+ std::cout << ts << " PASSED " << std::endl;
+ }
+ }
+
+ SECTION("from DIPHA file:") {
+ const char* file_name = "../tests/data/test_list.txt";
+ std::ifstream f;
+ f.open(file_name);
+ std::vector<TestFromFileCase> test_params;
+ std::string s;
+ while (std::getline(f, s)) {
+ test_params.emplace_back(s);
+ }
+
+ for(const auto& ts : test_params) {
+ params.wasserstein_power = ts.q;
+ params.internal_p = ts.internal_p;
+ bool read_file_A = hera::read_diagram_dipha<double, PairVector>(ts.file_1 + std::string(".pd.dipha"), 1, diagram_A);
+ bool read_file_B = hera::read_diagram_dipha<double, PairVector>(ts.file_2 + std::string(".pd.dipha"), 1, diagram_B);
+ REQUIRE( read_file_A );
+ REQUIRE( read_file_B );
+ double hera_answer = hera::wasserstein_dist(diagram_A, diagram_B, params);
+ REQUIRE( fabs(hera_answer - ts.answer) <= 0.01 * hera_answer );
+ std::cout << ts << " PASSED " << std::endl;
+ }
+ }
+}
+
+
+
+TEST_CASE("infinity points", "wasserstein_dist")
+{
+ PairVector diagram_A, diagram_B;
+ hera::AuctionParams<double> params;
+ params.wasserstein_power = 1.0;
+ params.delta = 0.01;
+ params.internal_p = hera::get_infinity<double>();
+ params.initial_epsilon = 0.0;
+ params.epsilon_common_ratio = 0.0;
+ params.max_num_phases = 30;
+ params.gamma_threshold = 0.0;
+ params.max_bids_per_round = 0; // use Jacobi
+
+ // do not use Hera's infinity! it is -1
+ double inf = std::numeric_limits<double>::infinity();
+
+ SECTION("two points at infinity, no finite points") {
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ double d = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double corr_answer = 1.0;
+ REQUIRE( fabs(d - corr_answer) <= 0.00000000001 );
+ }
+
+ SECTION("two points at infinity") {
+
+ // edge cost 3.0
+ diagram_A.emplace_back(10.0, 20.0); // (5, 5)
+ diagram_B.emplace_back(13.0, 19.0); // (3, 3)
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ double d = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double corr_answer = 1.0 + 3.0;
+ REQUIRE( fabs(d - corr_answer) <= 0.00000000001 );
+ }
+
+ SECTION("three points at infinity, no finite points") {
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ double d = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double corr_answer = inf;
+ REQUIRE( d == corr_answer );
+ }
+
+ SECTION("three points at infinity") {
+
+ // edge cost 3.0
+ diagram_A.emplace_back(10.0, 20.0); // (5, 5)
+ diagram_B.emplace_back(13.0, 19.0); // (3, 3)
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, inf);
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ double d = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double corr_answer = inf;
+ REQUIRE( d == corr_answer );
+ }
+
+
+ SECTION("all four corners at infinity, no finite points, finite answer") {
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_B.emplace_back(inf, 2.0);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(-inf, 1.0);
+ diagram_B.emplace_back(-inf, 2.0);
+
+ double d = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double corr_answer = 4.0;
+
+ REQUIRE( d == corr_answer );
+ }
+
+ SECTION("all four corners at infinity, no finite points, infinite answer-1") {
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, inf);
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_B.emplace_back(inf, 2.0);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(-inf, 1.0);
+ diagram_B.emplace_back(-inf, 2.0);
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ double corr_answer = inf;
+
+ REQUIRE( d1 == corr_answer );
+ REQUIRE( d2 == corr_answer );
+ }
+
+ SECTION("all four corners at infinity, no finite points, infinite answer-2") {
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_B.emplace_back(inf, 2.0);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(-inf, 1.0);
+ diagram_B.emplace_back(-inf, 2.0);
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ double corr_answer = inf;
+
+ REQUIRE( d1 == corr_answer );
+ REQUIRE( d2 == corr_answer );
+ }
+
+ SECTION("all four corners at infinity, no finite points, infinite answer-3") {
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_B.emplace_back(inf, 2.0);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(-inf, 1.0);
+ diagram_B.emplace_back(-inf, 2.0);
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ double corr_answer = inf;
+
+ REQUIRE( d1 == corr_answer );
+ REQUIRE( d2 == corr_answer );
+ }
+
+ SECTION("all four corners at infinity, no finite points, infinite answer-4") {
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(1.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_B.emplace_back(inf, 2.0);
+
+ // edge cost 1.0
+ diagram_A.emplace_back(-inf, 1.0);
+ diagram_B.emplace_back(-inf, 2.0);
+ diagram_B.emplace_back(-inf, 2.0);
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ double corr_answer = inf;
+
+ REQUIRE( d1 == corr_answer );
+ REQUIRE( d2 == corr_answer );
+ }
+
+ SECTION("all four corners at infinity, with finite points, infinite answer-1") {
+
+ diagram_A.emplace_back(1.0, inf);
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ diagram_A.emplace_back(1.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_B.emplace_back(inf, 2.0);
+
+ diagram_A.emplace_back(-inf, 1.0);
+ diagram_B.emplace_back(-inf, 2.0);
+
+ // finite edge
+ diagram_A.emplace_back(10.0, 20.0);
+ diagram_B.emplace_back(13.0, 19.0);
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ double corr_answer = inf;
+
+ REQUIRE( d1 == corr_answer );
+ REQUIRE( d2 == corr_answer );
+ }
+
+ SECTION("all four corners at infinity, with finite points, infinite answer-2") {
+
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ diagram_A.emplace_back(1.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_B.emplace_back(inf, 2.0);
+
+ diagram_A.emplace_back(-inf, 1.0);
+ diagram_B.emplace_back(-inf, 2.0);
+
+ // finite edge
+ diagram_A.emplace_back(10.0, 20.0);
+ diagram_B.emplace_back(13.0, 19.0);
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ double corr_answer = inf;
+
+ REQUIRE( d1 == corr_answer );
+ REQUIRE( d2 == corr_answer );
+ }
+
+ SECTION("all four corners at infinity, with finite points, infinite answer-3") {
+
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ diagram_A.emplace_back(1.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_B.emplace_back(inf, 2.0);
+
+ diagram_A.emplace_back(-inf, 1.0);
+ diagram_B.emplace_back(-inf, 2.0);
+
+ // finite edge
+ diagram_A.emplace_back(10.0, 20.0);
+ diagram_B.emplace_back(13.0, 19.0);
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ double corr_answer = inf;
+
+ REQUIRE( d1 == corr_answer );
+ REQUIRE( d2 == corr_answer );
+ }
+
+ SECTION("all four corners at infinity, no finite points, infinite answer-4") {
+
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ diagram_A.emplace_back(1.0, -inf);
+ diagram_B.emplace_back(2.0, -inf);
+
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_B.emplace_back(inf, 2.0);
+
+ diagram_A.emplace_back(-inf, 1.0);
+ diagram_B.emplace_back(-inf, 2.0);
+ diagram_B.emplace_back(-inf, 2.0);
+
+ // finite edge
+ diagram_A.emplace_back(10.0, 20.0);
+ diagram_B.emplace_back(13.0, 19.0);
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ double corr_answer = inf;
+
+ REQUIRE( d1 == corr_answer );
+ REQUIRE( d2 == corr_answer );
+ }
+
+
+ SECTION("simple small example with finite answer") {
+ diagram_A.emplace_back(1.0, inf);
+ diagram_B.emplace_back(2.0, inf);
+
+ diagram_A.emplace_back(1.9, inf);
+ diagram_B.emplace_back(1.1, inf);
+
+ // 1.1 - 1.0 + 2.0 - 1.9 = 0.2
+
+ diagram_A.emplace_back(inf, 1.0);
+ diagram_B.emplace_back(inf, 2.0);
+
+ diagram_A.emplace_back(inf, 1.9);
+ diagram_B.emplace_back(inf, 1.1);
+
+
+ // finite edge
+ diagram_A.emplace_back(10.0, 20.0);
+ diagram_B.emplace_back(13.0, 19.0);
+
+ double d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ double d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ double corr_answer = 3.0 + 0.2 + 0.2;
+
+ REQUIRE( d1 == corr_answer );
+ REQUIRE( d2 == corr_answer );
+
+ params.wasserstein_power = 2.0;
+
+ d1 = hera::wasserstein_dist<>(diagram_A, diagram_B, params);
+ d2 = hera::wasserstein_dist<>(diagram_B, diagram_A, params);
+ corr_answer = std::sqrt(3.0 * 3.0 + 4 * 0.1 * 0.1);
+
+ REQUIRE( fabs(d1 - corr_answer) < 0.000000000001 );
+ REQUIRE( fabs(d2 - corr_answer) < 0.000000000001 );
+
+ }
+
+}
+
diff --git a/wasserstein/tests/test_hera_wasserstein_pure_geom.cpp b/wasserstein/tests/test_hera_wasserstein_pure_geom.cpp
new file mode 100644
index 0000000..9603ceb
--- /dev/null
+++ b/wasserstein/tests/test_hera_wasserstein_pure_geom.cpp
@@ -0,0 +1,111 @@
+#include "catch/catch.hpp"
+
+#include <sstream>
+#include <iostream>
+
+
+#undef LOG_AUCTION
+
+#include "wasserstein_pure_geom.hpp"
+#include "tests_reader.h"
+
+using namespace hera_test;
+
+TEST_CASE("simple point clouds", "wasserstein_dist_pure_geom")
+{
+// int n_points = 3;
+// int dim = 3;
+// using Traits = hera::ws::dnn::DynamicPointTraits<double>;
+// hera::ws::dnn::DynamicPointTraits<double> traits(dim);
+// hera::ws::dnn::DynamicPointVector<double> dgm_a = traits.container(n_points);
+// hera::ws::dnn::DynamicPointVector<double> dgm_b = traits.container(n_points);
+//
+// dgm_a[0][0] = 0.0;
+// dgm_a[0][1] = 0.0;
+// dgm_a[0][2] = 0.0;
+//
+// dgm_a[1][0] = 1.0;
+// dgm_a[1][1] = 0.0;
+// dgm_a[1][2] = 0.0;
+//
+// dgm_a[2][0] = 0.0;
+// dgm_a[2][1] = 1.0;
+// dgm_a[2][2] = 1.0;
+//
+// dgm_b[0][0] = 0.0;
+// dgm_b[0][1] = 0.1;
+// dgm_b[0][2] = 0.1;
+//
+// dgm_b[1][0] = 1.1;
+// dgm_b[1][1] = 0.0;
+// dgm_b[1][2] = 0.0;
+//
+// dgm_b[2][0] = 0.0;
+// dgm_b[2][1] = 1.1;
+// dgm_b[2][2] = 0.9;
+
+ const int dim = 3;
+ using Traits = hera::ws::dnn::DynamicPointTraits<double>;
+ hera::ws::dnn::DynamicPointTraits<double> traits(dim);
+ hera::AuctionParams<double> params;
+ params.dim = dim;
+ params.wasserstein_power = 1.0;
+ params.delta = 0.01;
+ params.internal_p = hera::get_infinity<double>();
+ params.initial_epsilon = 0.0;
+ params.epsilon_common_ratio = 0.0;
+ params.max_num_phases = 30;
+ params.gamma_threshold = 0.0;
+ params.max_bids_per_round = 0; // use Jacobi
+
+
+ SECTION("trivial: two single-point diagrams-1") {
+
+ int n_points = 1;
+ hera::ws::dnn::DynamicPointVector<double> dgm_a = traits.container(n_points);
+ hera::ws::dnn::DynamicPointVector<double> dgm_b = traits.container(n_points);
+
+ dgm_a[0][0] = 0.0;
+ dgm_a[0][1] = 0.0;
+ dgm_a[0][2] = 0.0;
+
+ dgm_b[0][0] = 1.0;
+ dgm_b[0][1] = 1.0;
+ dgm_b[0][2] = 1.0;
+
+ std::vector<size_t> max_bids { 1, 10, 0 };
+ std::vector<int> internal_ps{ 1, 2, static_cast<int>(hera::get_infinity()) };
+ std::vector<double> wasserstein_powers { 1, 2, 3 };
+
+ for(auto internal_p : internal_ps) {
+ // there is only one point, so the answer does not depend wasserstein power
+ double correct_answer;
+ switch (internal_p) {
+ case 1 :
+ correct_answer = 3.0;
+ break;
+ case 2 :
+ correct_answer = sqrt(3.0);
+ break;
+ case static_cast<int>(hera::get_infinity()) :
+ correct_answer = 1.0;
+ break;
+ default :
+ throw std::runtime_error("Correct answer not specified in test case");
+ }
+
+ for (auto max_bid : max_bids) {
+ for (auto wasserstein_power : wasserstein_powers) {
+ params.max_bids_per_round = max_bid;
+ params.internal_p = internal_p;
+ params.wasserstein_power = wasserstein_power;
+ double d1 = hera::ws::wasserstein_dist(dgm_a, dgm_b, params);
+ double d2 = hera::ws::wasserstein_dist(dgm_b, dgm_a, params);
+ REQUIRE(fabs(d1 - d2) <= 0.00000000001);
+ REQUIRE(fabs(d1 - correct_answer) <= 0.00000000001);
+ }
+ }
+ }
+ }
+}
+
diff --git a/wasserstein/tests/tests_main.cpp b/wasserstein/tests/tests_main.cpp
new file mode 100644
index 0000000..d24407e
--- /dev/null
+++ b/wasserstein/tests/tests_main.cpp
@@ -0,0 +1,3 @@
+#define LOG_AUCTION
+#define CATCH_CONFIG_MAIN
+#include "catch/catch.hpp"
diff --git a/wasserstein/tests/tests_reader.h b/wasserstein/tests/tests_reader.h
new file mode 100644
index 0000000..f2d5735
--- /dev/null
+++ b/wasserstein/tests/tests_reader.h
@@ -0,0 +1,67 @@
+#ifndef WASSERSTEIN_TESTS_READER_H
+#define WASSERSTEIN_TESTS_READER_H
+
+#include <vector>
+#include <string>
+#include <ostream>
+#include <iostream>
+#include <sstream>
+#include <cassert>
+#include <cmath>
+
+#include "hera_infinity.h"
+
+namespace hera_test {
+ inline std::vector<std::string> split_on_delim(const std::string& s, char delim)
+ {
+ std::stringstream ss(s);
+ std::string token;
+ std::vector<std::string> tokens;
+ while (std::getline(ss, token, delim)) {
+ tokens.push_back(token);
+ }
+ return tokens;
+ }
+
+
+ // single row in a file with test cases
+ struct TestFromFileCase
+ {
+
+ std::string file_1;
+ std::string file_2;
+ double q;
+ double internal_p;
+ double answer;
+
+ TestFromFileCase(std::string s)
+ {
+ auto tokens = split_on_delim(s, ' ');
+ assert(tokens.size() == 5);
+
+ file_1 = tokens.at(0);
+ file_2 = tokens.at(1);
+ q = std::stod(tokens.at(2));
+ internal_p = std::stod(tokens.at(3));
+ answer = std::stod(tokens.at(4));
+
+ if (q < 1.0 or std::isinf(q) or
+ (internal_p != hera::get_infinity<double>() and internal_p < 1.0)) {
+ throw std::runtime_error("Bad line in test_list.txt");
+ }
+ }
+ };
+
+ inline std::ostream& operator<<(std::ostream& out, const TestFromFileCase& s)
+ {
+ out << "[" << s.file_1 << ", " << s.file_2 << ", q = " << s.q << ", norm = ";
+ if (s.internal_p != hera::get_infinity()) {
+ out << s.internal_p;
+ } else {
+ out << "infinity";
+ }
+ out << ", answer = " << s.answer << "]";
+ return out;
+ }
+} // namespace hera_test
+#endif //WASSERSTEIN_TESTS_READER_H