[mathic] 02/62: Initial commit of Mathic code.
Doug Torrance
dtorrance-guest at moszumanska.debian.org
Wed Apr 1 11:36:17 UTC 2015
This is an automated email from the git hooks/post-receive script.
dtorrance-guest pushed a commit to branch master
in repository mathic.
commit f7bd26d658416b540ff5fd69fa04597a43131bcf
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date: Sun Jul 8 01:14:15 2012 -0400
Initial commit of Mathic code.
---
Makefile.am | 104 ++++
autogen.sh | 3 +
build/autotools/mathic.pc.in | 12 +
build/vc10/divsim/divsim.vcxproj | 133 +++++
build/vc10/divsim/divsim.vcxproj.filters | 153 ++++++
build/vc10/divsim/divsim.vcxproj.user | 3 +
build/vc10/mathic.sln | 26 +
build/vc10/pqsim/pqsim.vcxproj | 114 +++++
configure.ac | 79 +++
fixspace | 51 ++
include/mathic/mathic.cpp | 17 +
include/mathic/mathic.h | 27 ++
replace | 11 +
src/divsim/DivListModel.h | 195 ++++++++
src/divsim/KDTreeModel.h | 193 ++++++++
src/divsim/Monomial.h | 52 ++
src/divsim/Simulation.cpp | 62 +++
src/divsim/Simulation.h | 310 ++++++++++++
src/divsim/divMain.cpp | 148 ++++++
src/divsim/divMain.h | 6 +
src/divsim/stdinc.h | 57 +++
src/mathic.h | 27 ++
src/mathic/Action.cpp | 17 +
src/mathic/Action.h | 46 ++
src/mathic/BinaryKDTree.h | 780 ++++++++++++++++++++++++++++++
src/mathic/BoolParameter.cpp | 31 ++
src/mathic/BoolParameter.h | 31 ++
src/mathic/CliParameter.cpp | 19 +
src/mathic/CliParameter.h | 29 ++
src/mathic/CliParser.cpp | 101 ++++
src/mathic/CliParser.h | 50 ++
src/mathic/ColumnPrinter.cpp | 185 +++++++
src/mathic/ColumnPrinter.h | 64 +++
src/mathic/ComTree.h | 273 +++++++++++
src/mathic/Comparer.h | 18 +
src/mathic/DivFinder.h | 74 +++
src/mathic/DivList.h | 616 +++++++++++++++++++++++
src/mathic/DivMask.cpp | 14 +
src/mathic/DivMask.h | 463 ++++++++++++++++++
src/mathic/ElementDeleter.cpp | 1 +
src/mathic/ElementDeleter.h | 138 ++++++
src/mathic/GeoFront.h | 375 ++++++++++++++
src/mathic/Geobucket.h | 805 +++++++++++++++++++++++++++++++
src/mathic/Heap.h | 200 ++++++++
src/mathic/HelpAction.cpp | 113 +++++
src/mathic/HelpAction.h | 34 ++
src/mathic/IntegerParameter.cpp | 36 ++
src/mathic/IntegerParameter.h | 31 ++
src/mathic/KDEntryArray.h | 493 +++++++++++++++++++
src/mathic/KDTree.h | 366 ++++++++++++++
src/mathic/NameFactory.cpp | 1 +
src/mathic/NameFactory.h | 201 ++++++++
src/mathic/PackedKDTree.h | 760 +++++++++++++++++++++++++++++
src/mathic/StlSet.h | 68 +++
src/mathic/StringParameter.cpp | 22 +
src/mathic/StringParameter.h | 32 ++
src/mathic/Timer.cpp | 51 ++
src/mathic/Timer.h | 44 ++
src/mathic/TourTree.h | 261 ++++++++++
src/mathic/display.cpp | 145 ++++++
src/mathic/display.h | 41 ++
src/mathic/error.cpp | 22 +
src/mathic/error.h | 56 +++
src/mathic/main.cpp | 17 +
src/mathic/stdinc.h | 26 +
src/pqsim/GeobucketModel.h | 68 +++
src/pqsim/HeapModel.h | 16 +
src/pqsim/Item.cpp | 9 +
src/pqsim/Item.h | 110 +++++
src/pqsim/Model.cpp | 2 +
src/pqsim/Model.h | 202 ++++++++
src/pqsim/Simulator.cpp | 326 +++++++++++++
src/pqsim/Simulator.h | 103 ++++
src/pqsim/StlSetModel.h | 10 +
src/pqsim/TourTreeModel.h | 16 +
src/pqsim/pqMain.cpp | 65 +++
src/pqsim/pqMain.h | 6 +
src/pqsim/stdinc.h | 48 ++
src/test/DivFinder.cpp | 10 +
src/test/gtestInclude.cpp | 10 +
src/test/testMain.cpp | 6 +
81 files changed, 9940 insertions(+)
diff --git a/Makefile.am b/Makefile.am
new file mode 100755
index 0000000..2b31892
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,104 @@
+# options passed to aclocal, which is a tool for making macroes visible to
+# autoconf. We use -I to tell aclocal where we put the local macros.
+ACLOCAL_AMFLAGS = -I build/autotools/m4
+
+# Options passed to the C PreProcessor (CPP), NOT the C Plus Plus compiler.
+AM_CPPFLAGS = -I${top_srcdir}/
+libmathic_ at MATHIC_API_VERSION@_la_CPPFLAGS = $(DEPS_CFLAGS)
+
+# tell Libtool what the name of the library is.
+lib_LTLIBRARIES = libmathic- at MATHIC_API_VERSION@.la
+
+# set the C++ compiler to include src/
+AM_CXXFLAGS=-I$(top_srcdir)/src/
+
+# set the linker flags to build libmathic
+#libmathic_ at MATHIC_API_VERSION@_la_LDFLAGS =
+
+# libraries that are needed by this library
+libmathic_ at MATHIC_API_VERSION@_la_LIBADD= $(DEPS_LIBS)
+
+# the sources that are built to make libmathic
+libmathic_ at MATHIC_API_VERSION@_la_SOURCES = src/mathic/Timer.cpp \
+ src/mathic/ColumnPrinter.cpp src/mathic/DivMask.cpp \
+ src/mathic/Action.cpp src/mathic/BoolParameter.cpp \
+ src/mathic/CliParameter.cpp src/mathic/CliParser.cpp \
+ src/mathic/ElementDeleter.cpp src/mathic/NameFactory.cpp \
+ src/mathic/error.cpp src/mathic/HelpAction.cpp \
+ src/mathic/IntegerParameter.cpp src/mathic/StringParameter.cpp \
+ src/mathic/display.cpp
+
+# The headers that libmathic installs.
+# Normally, automake strips the path from the files when installing them,
+# so src/mathic/x.h gets installed as just x.h.
+mathicA_include_HEADERS = src/mathic.h
+mathicA_includedir = $(includedir)/mathic-$(MATHIC_API_VERSION)
+# install remaining headers into subdirectory of the include dir
+mathicB_includedir = \
+ $(includedir)/mathic-$(MATHIC_API_VERSION)/mathic
+mathicB_include_HEADERS = src/mathic/stdinc.h src/mathic/Timer.h \
+ src/mathic/ColumnPrinter.h src/mathic/ElementDeleter.h \
+ src/mathic/error.h src/mathic/DivList.h src/mathic/KDTree.h \
+ src/mathic/TourTree.h src/mathic/StlSet.h src/mathic/Heap.h \
+ src/mathic/Geobucket.h src/mathic/Action.h src/mathic/DivMask.h \
+ src/mathic/BoolParameter.h src/mathic/CliParameter.h \
+ src/mathic/CliParser.h src/mathic/HelpAction.h \
+ src/mathic/IntegerParameter.h src/mathic/StringParameter.h \
+ src/mathic/display.h src/mathic/NameFactory.h
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = build/autotools/mathic-$(MATHIC_API_VERSION).pc
+
+# When making a distribution file, Automake knows to include all files
+# that are necessary to build the project. EXTRA_DIST specifies files
+# to include beyond those used in the build process.
+EXTRA_DIST = autogen.sh
+
+# tell automake what programs are there that are not built automatically
+EXTRA_PROGRAMS = pqsim divsim
+
+# set up the divisor query simulation
+divsim_CPPFLAGS = $(DEPS_CFLAGS)
+divsim_SOURCES = src/divsim/divMain.cpp src/divsim/Simulation.cpp
+divsim_LDADD = $(top_builddir)/libmathic-$(MATHIC_API_VERSION).la
+
+# set up the priority queue simulation
+pqsim_CPPFLAGS = $(DEPS_CFLAGS)
+pqsim_SOURCES = src/pqsim/Item.cpp src/pqsim/Model.cpp \
+ src/pqsim/pqMain.cpp src/pqsim/Simulator.cpp
+pqsim_LDADD = $(top_builddir)/libmathic-$(MATHIC_API_VERSION).la
+
+
+# set up tests to run on "make check"
+TESTS=unittest
+check_PROGRAMS=$(TESTS)
+
+unittest_CPPFLAGS = $(DEPS_CFLAGS)
+unittest_CXXFLAGS=\
+ -I$(top_srcdir)/libs/gtest/include\
+ -I$(top_srcdir)/libs/gtest/\
+ -I$(top_srcdir)/src/
+unittest_LDADD = $(DEPS_LIBS)
+unittest_LDFLAGS= $(top_builddir)/libmathic-$(MATHIC_API_VERSION).la
+
+test_LIBS=
+unittest_SOURCES=src/test/DivFinder.cpp src/test/gtestInclude.cpp \
+src/test/testMain.cpp
+
+# allow to download gtest in case of needing to run unit tests
+GTEST_DIR = $(top_srcdir)/libs/
+GTEST_TMP_DIR = $(top_srcdir)/libs/
+GTEST_VERSION = 1.6.0
+GTEST_DOWNLOAD_FILE = gtest-$(GTEST_VERSION).zip
+gtest: $(GTEST_DIR)/gtest
+$(GTEST_DIR)/gtest:
+ mkdir -p $(GTEST_TMP_DIR);
+ rm -rf $(GTEST_TMP_DIR)/$(GTEST_DOWNLOAD_FILE);
+ rm -rf $(GTEST_TMP_DIR)/gtest-$(GTEST_VERSION);
+ rm -rf $(GTEST_TMP_DIR)/gtest;
+ (cd $(GTEST_TMP_DIR); \
+ wget http://googletest.googlecode.com/files/$(GTEST_DOWNLOAD_FILE); \
+ unzip $(GTEST_DOWNLOAD_FILE);)
+ rm -rf $(GTEST_DIR)/gtest;
+ mv $(GTEST_TMP_DIR)/gtest-$(GTEST_VERSION) $(GTEST_DIR)/gtest;
+.PHONY: gtest
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..a8f9bcb
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+autoreconf --verbose --install --force `dirname "$0"`
diff --git a/build/autotools/mathic.pc.in b/build/autotools/mathic.pc.in
new file mode 100755
index 0000000..07b91c4
--- /dev/null
+++ b/build/autotools/mathic.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: mathic
+Description: C++ library of symbolic algebra data structures for use in Groebner basis computation.
+URL: https://github.com/broune/mathic
+Requires: memtailor-1.0
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lmathic- at MATHIC_API_VERSION@
+Cflags: -I${includedir}/mathic- at MATHIC_API_VERSION@/
diff --git a/build/vc10/divsim/divsim.vcxproj b/build/vc10/divsim/divsim.vcxproj
new file mode 100755
index 0000000..e2e0ee2
--- /dev/null
+++ b/build/vc10/divsim/divsim.vcxproj
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{CEF324F2-5D58-48DE-A67F-C7EB21E0737E}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>mathic</RootNamespace>
+ <ProjectName>divsim</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>D:\key\projs\mathic\libs\memtailor\include;D:\key\projs\mathic\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <MinimalRebuild>false</MinimalRebuild>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>D:\key\projs\mathic\libs\memtailor\include;D:\key\projs\mathic\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\Action.cpp" />
+ <ClCompile Include="..\..\src\BoolParameter.cpp" />
+ <ClCompile Include="..\..\src\CliParameter.cpp" />
+ <ClCompile Include="..\..\src\CliParser.cpp" />
+ <ClCompile Include="..\..\src\ColumnPrinter.cpp" />
+ <ClCompile Include="..\..\src\display.cpp" />
+ <ClCompile Include="..\..\src\DivMask.cpp" />
+ <ClCompile Include="..\..\src\divsim\divMain.cpp" />
+ <ClCompile Include="..\..\src\divsim\Simulation.cpp" />
+ <ClCompile Include="..\..\src\ElementDeleter.cpp" />
+ <ClCompile Include="..\..\src\error.cpp" />
+ <ClCompile Include="..\..\src\HelpAction.cpp" />
+ <ClCompile Include="..\..\src\IntegerParameter.cpp" />
+ <ClCompile Include="..\..\src\libs\memtailor.cpp" />
+ <ClCompile Include="..\..\src\NameFactory.cpp" />
+ <ClCompile Include="..\..\src\StringParameter.cpp" />
+ <ClCompile Include="..\..\src\Timer.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\src\Action.h" />
+ <ClInclude Include="..\..\src\BinaryKDTree.h" />
+ <ClInclude Include="..\..\src\BoolParameter.h" />
+ <ClInclude Include="..\..\src\CliParameter.h" />
+ <ClInclude Include="..\..\src\CliParser.h" />
+ <ClInclude Include="..\..\src\ColumnPrinter.h" />
+ <ClInclude Include="..\..\src\Comparer.h" />
+ <ClInclude Include="..\..\src\display.h" />
+ <ClInclude Include="..\..\src\DivFinder.h" />
+ <ClInclude Include="..\..\src\DivList.h" />
+ <ClInclude Include="..\..\src\DivMask.h" />
+ <ClInclude Include="..\..\src\divsim\DivListModel.h" />
+ <ClInclude Include="..\..\src\divsim\KDTreeModel.h" />
+ <ClInclude Include="..\..\src\divsim\Monomial.h" />
+ <ClInclude Include="..\..\src\divsim\Simulation.h" />
+ <ClInclude Include="..\..\src\divsim\stdinc.h" />
+ <ClInclude Include="..\..\src\ElementDeleter.h" />
+ <ClInclude Include="..\..\src\error.h" />
+ <ClInclude Include="..\..\src\HelpAction.h" />
+ <ClInclude Include="..\..\src\IntegerParameter.h" />
+ <ClInclude Include="..\..\src\KDEntryArray.h" />
+ <ClInclude Include="..\..\src\KDTree.h" />
+ <ClInclude Include="..\..\src\NameFactory.h" />
+ <ClInclude Include="..\..\src\PackedKDTree.h" />
+ <ClInclude Include="..\..\src\stdinc.h" />
+ <ClInclude Include="..\..\src\StringParameter.h" />
+ <ClInclude Include="..\..\src\Timer.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/build/vc10/divsim/divsim.vcxproj.filters b/build/vc10/divsim/divsim.vcxproj.filters
new file mode 100755
index 0000000..7361366
--- /dev/null
+++ b/build/vc10/divsim/divsim.vcxproj.filters
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\ColumnPrinter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\Timer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\divsim\divMain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\divsim\Simulation.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\libs\memtailor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\DivMask.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\Action.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\CliParser.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\BoolParameter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\CliParameter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\ElementDeleter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\error.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\NameFactory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\HelpAction.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\display.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\IntegerParameter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\StringParameter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\src\ColumnPrinter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\Comparer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\DivFinder.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\DivList.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\DivMask.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\KDTree.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\stdinc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\Timer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\divsim\DivListModel.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\divsim\KDTreeModel.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\divsim\Monomial.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\divsim\Simulation.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\divsim\stdinc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\BinaryKDTree.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\KDEntryArray.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\PackedKDTree.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\Action.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\CliParser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\BoolParameter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\CliParameter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\ElementDeleter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\error.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\NameFactory.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\HelpAction.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\display.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\IntegerParameter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\StringParameter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/build/vc10/divsim/divsim.vcxproj.user b/build/vc10/divsim/divsim.vcxproj.user
new file mode 100755
index 0000000..695b5c7
--- /dev/null
+++ b/build/vc10/divsim/divsim.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
\ No newline at end of file
diff --git a/build/vc10/mathic.sln b/build/vc10/mathic.sln
new file mode 100755
index 0000000..ad8a08f
--- /dev/null
+++ b/build/vc10/mathic.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "divsim", "divsim\divsim.vcxproj", "{CEF324F2-5D58-48DE-A67F-C7EB21E0737E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pqsim", "pqsim\pqsim.vcxproj", "{1B6A84DF-114E-46A3-B868-04F203156CF4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CEF324F2-5D58-48DE-A67F-C7EB21E0737E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CEF324F2-5D58-48DE-A67F-C7EB21E0737E}.Debug|Win32.Build.0 = Debug|Win32
+ {CEF324F2-5D58-48DE-A67F-C7EB21E0737E}.Release|Win32.ActiveCfg = Release|Win32
+ {CEF324F2-5D58-48DE-A67F-C7EB21E0737E}.Release|Win32.Build.0 = Release|Win32
+ {1B6A84DF-114E-46A3-B868-04F203156CF4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1B6A84DF-114E-46A3-B868-04F203156CF4}.Debug|Win32.Build.0 = Debug|Win32
+ {1B6A84DF-114E-46A3-B868-04F203156CF4}.Release|Win32.ActiveCfg = Release|Win32
+ {1B6A84DF-114E-46A3-B868-04F203156CF4}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/build/vc10/pqsim/pqsim.vcxproj b/build/vc10/pqsim/pqsim.vcxproj
new file mode 100755
index 0000000..c61a38b
--- /dev/null
+++ b/build/vc10/pqsim/pqsim.vcxproj
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{1B6A84DF-114E-46A3-B868-04F203156CF4}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>pqsim</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>D:\key\projs\mathic\src;D:\key\projs\mathic\libs\memtailor\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>D:\key\projs\mathic\src;D:\key\projs\mathic\libs\memtailor\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\ColumnPrinter.cpp" />
+ <ClCompile Include="..\..\src\libs\memtailor.cpp" />
+ <ClCompile Include="..\..\src\pqsim\Item.cpp" />
+ <ClCompile Include="..\..\src\pqsim\Model.cpp" />
+ <ClCompile Include="..\..\src\pqsim\pqMain.cpp" />
+ <ClCompile Include="..\..\src\pqsim\Simulator.cpp" />
+ <ClCompile Include="..\..\src\Timer.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\src\ColumnPrinter.h" />
+ <ClInclude Include="..\..\src\Comparer.h" />
+ <ClInclude Include="..\..\src\ComTree.h" />
+ <ClInclude Include="..\..\src\DivFinder.h" />
+ <ClInclude Include="..\..\src\Geobucket.h" />
+ <ClInclude Include="..\..\src\GeoFront.h" />
+ <ClInclude Include="..\..\src\Heap.h" />
+ <ClInclude Include="..\..\src\pqsim\GeobucketModel.h" />
+ <ClInclude Include="..\..\src\pqsim\HeapModel.h" />
+ <ClInclude Include="..\..\src\pqsim\Item.h" />
+ <ClInclude Include="..\..\src\pqsim\Model.h" />
+ <ClInclude Include="..\..\src\pqsim\pqMain.h" />
+ <ClInclude Include="..\..\src\pqsim\Simulator.h" />
+ <ClInclude Include="..\..\src\pqsim\stdinc.h" />
+ <ClInclude Include="..\..\src\pqsim\StlSetModel.h" />
+ <ClInclude Include="..\..\src\pqsim\TourTreeModel.h" />
+ <ClInclude Include="..\..\src\stdinc.h" />
+ <ClInclude Include="..\..\src\StlSet.h" />
+ <ClInclude Include="..\..\src\Timer.h" />
+ <ClInclude Include="..\..\src\TourTree.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/configure.ac b/configure.ac
new file mode 100755
index 0000000..a1524f1
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,79 @@
+dnl AC_INIT sets up autoconf and must be first macro.
+AC_INIT([mathic], [1.0]) # package, version, bug-report-email
+
+# Check that memtailor is installed and locate it
+PKG_CHECK_MODULES([DEPS], [memtailor-1.0])
+
+# set up information about directories
+AC_CONFIG_MACRO_DIR([build/autotools/m4]) # directory of extra autoconf macroes
+AC_CONFIG_AUX_DIR([build/autotools]) # directory for auxiliary build tools (install-sh etc)
+
+# check that source directory is correct
+dnl if autoconf is told the source code is in a directory that does not
+dnl contain this file then it knows that the directory is wrong.
+AC_CONFIG_SRCDIR([src/mathic.h])
+
+# Enable optional maintainer mode (off by default)
+dnl AM_MAINTAINER_MODE turns off automatic reconstruction of the build
+dnl files if the source build files have changed. A developer will want
+dnl those automatic reconstructions to happen so that changes to the
+dnl build system are actually carried out. However, a user might not
+dnl have the tools required to reconfigure and the need for
+dnl reconstruction might be spurious if the last-modified date is set
+dnl incorrectly on the build files.
+dnl
+dnl Passing the option [enable] to AM_MAINTAINER_MODE makes the
+dnl non-reconstruction feature available, but only when turned on by
+dnl passing the option –disable-maintainer-mode. This option is
+dnl apparently useful to some package distributors.
+AM_MAINTAINER_MODE([enable])
+
+# Set up Automake
+dnl foreign: do not create the GNU-specific file COPYING and do not complain
+dnl that GNU-specific files like NEWS, README, AUTHORS and ChangeLog are
+dnl missing.
+dnl -Wall: set Automake to emit all warnings it can. Is NOT RELATED to setting
+dnl warnings for other tools. For example, it wil not make the compiler
+dnl get a -Wall option.
+dnl subdir-objects: Put object files in a directory structure based on
+dnl the directory structure of the source files. This way, two source
+dnl files with the same name in different directories do not conflict.
+AM_INIT_AUTOMAKE([foreign subdir-objects -Wall])
+
+# Set up the $(LN_S) macro, which creates symbolic links
+AC_PROG_LN_S
+
+# set output variable INSTALL to the name of a BSD-compatible install program.
+# Requires install-sh to be present as a fallback, even on systems where
+# the fallback is not used.
+AC_PROG_INSTALL
+
+# Locate the C++ compiler.
+AC_PROG_CXX
+
+# Locate the archiver. This is only necessary in case of using an
+# unusual archiver such as Microsoft lib.
+AM_PROG_AR
+
+# Set up LibTool
+LT_INIT
+
+dnl Set the version for the library -- this concerns compatibility of the
+dnl source and binary interface of the library and is not the same as the
+dnl version of the project.
+AC_SUBST([MATHIC_SO_VERSION], [0:0:0])
+
+dnl Set the version displayed in the pkg-config file. This is currently
+dnl the same as the version of the project but it is possible that
+dnl for example the project will gain a version like x.y.z but that
+dnl the pkg-config file is only named as foo-x.y.pc (no z).
+AC_SUBST([MATHIC_API_VERSION], [1.0])
+
+dnl Set up AC_OUTPUT to create each file by copying an input file
+dnl while substituting the output variable values.
+AC_CONFIG_FILES([Makefile
+ build/autotools/mathic-${MATHIC_API_VERSION}.pc:build/autotools/mathic.pc.in])
+
+dnl Macro that is required to be at the end of any Autoconf script.
+dnl Creates config.status and launches it.
+AC_OUTPUT
diff --git a/fixspace b/fixspace
new file mode 100755
index 0000000..0228dcd
--- /dev/null
+++ b/fixspace
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+# Does the following operations on the files passed as arguments:
+# - Remove trailing space from lines
+# - Remove trailing blank lines
+# - Remove/convert DOS-style line breaks
+# - Expand tabs to spaces with a tabspace of 8
+
+# I once had an error where the conversion had an error (the computer
+# didn't have dos2unix), resulting in the converted files being empty.
+# The result was that every file got replaced by an empty file! That
+# was not so nice, so this script stops operation as soon as any error
+# occurs, and it also checks that only space has been changed before
+# it overwrites the original file with a space-fixed version.
+
+for f in $*; do echo $f;
+
+ tr -d '\r' < $f > __spaceTmp0;
+ if [ $? != 0 ]; then echo "There was an error removing DOS-style line breaks."; exit 1; fi;
+
+ expand -4 < __spaceTmp0 > __spaceTmp1;
+ if [ $? != 0 ]; then echo "There was an error expanding tabs."; exit 1; fi;
+
+ sed 's/[[:blank:]]*$//g' < __spaceTmp1 > __spaceTmp2;
+ if [ $? != 0 ]; then echo "There was an error eliminating trailing space from lines."; exit 1; fi;
+
+ # Make completely sure that we only changed the spaces
+ diff -EbwB -q $f __spaceTmp2;
+ if [ $? != 0 ]; then echo "There was an error. Conversion not confirmed correct."; exit 1; fi;
+
+ sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' < __spaceTmp2 > __spaceTmp3;
+ if [ $? != 0 ]; then echo "There was an error eliminating trailing blank lines."; exit 1; fi;
+
+ # We have to do diff twice, because diff will not ignore trailing
+ # lines that consist only of spaces. It will ignore changes to space and removal of
+ # completely empty lines, so if we do it twice we get the right thing.
+
+ # Make completely sure that we only changed the spaces
+ diff -EbwB -q __spaceTmp2 __spaceTmp3;
+ if [ $? != 0 ]; then echo "There was an error. Conversion not confirmed correct."; exit 1; fi;
+
+ diff -q $f __spaceTmp3 1>/dev/null;
+ if [ $? != 0 ]; then
+ mv -f __spaceTmp3 $f;
+ if [ $? != 0 ]; then echo "There was an error moving fixed file into place."; exit 1; fi;
+ echo "Fixed space issue for $f."
+ fi
+
+ rm -f __spaceTmp0 __spaceTmp1 __spaceTmp2 __spaceTmp3;
+ if [ $? != 0 ]; then echo "There was an error removing temporary files."; exit 1; fi;
+done;
diff --git a/include/mathic/mathic.cpp b/include/mathic/mathic.cpp
new file mode 100755
index 0000000..97f7d37
--- /dev/null
+++ b/include/mathic/mathic.cpp
@@ -0,0 +1,17 @@
+// This implementation file includes all the implementation files needed
+// to get MemTailor working.
+#include "mathic.h"
+#include "../../src/Timer.cpp"
+#include "../../src/ColumnPrinter.cpp"
+#include "../../src/DivMask.cpp"
+#include "../../src/Action.cpp"
+#include "../../src/BoolParameter.cpp"
+#include "../../src/CliParameter.cpp"
+#include "../../src/CliParser.cpp"
+#include "../../src/ElementDeleter.cpp"
+#include "../../src/NameFactory.cpp"
+#include "../../src/error.cpp"
+#include "../../src/HelpAction.cpp"
+#include "../../src/IntegerParameter.cpp"
+#include "../../src/StringParameter.cpp"
+#include "../../src/display.cpp"
diff --git a/include/mathic/mathic.h b/include/mathic/mathic.h
new file mode 100755
index 0000000..4d46862
--- /dev/null
+++ b/include/mathic/mathic.h
@@ -0,0 +1,27 @@
+// Include this file to pull in all external MemTailor files
+
+// utilities
+#include "../../src/Timer.h"
+#include "../../src/ColumnPrinter.h"
+#include "../../src/ElementDeleter.h"
+#include "../../src/error.h"
+
+// divisor query data structures
+#include "../../src/DivList.h"
+#include "../../src/KDTree.h"
+
+// priority queue data structures
+#include "../../src/TourTree.h"
+#include "../../src/StlSet.h"
+#include "../../src/Heap.h"
+#include "../../src/Geobucket.h"
+
+// CLI package
+#include "../../src/Action.h"
+#include "../../src/BoolParameter.h"
+#include "../../src/CliParameter.h"
+#include "../../src/CliParser.h"
+#include "../../src/HelpAction.h"
+#include "../../src/IntegerParameter.h"
+#include "../../src/StringParameter.h"
+#include "../../src/display.h"
diff --git a/replace b/replace
new file mode 100755
index 0000000..fb8bd7e
--- /dev/null
+++ b/replace
@@ -0,0 +1,11 @@
+#!/bin/bash
+echo "Running script \"sed s/$1/$2/\""
+for i in 1 2 3; do
+ /usr/bin/sleep 1; echo -n .;
+done
+
+for f in `ls src/*.cpp src/*.h`; do
+ echo "Processing $f";
+ sed "s/$1/$2/" < $f > $f.tmp
+ mv $f.tmp $f
+done
diff --git a/src/divsim/DivListModel.h b/src/divsim/DivListModel.h
new file mode 100755
index 0000000..eda34db
--- /dev/null
+++ b/src/divsim/DivListModel.h
@@ -0,0 +1,195 @@
+#ifndef DIV_ARRAY_MODEL_GUARD
+#define DIV_ARRAY_MODEL_GUARD
+
+#include "Monomial.h"
+#include "mathic/DivList.h"
+#include <string>
+#include <vector>
+
+/** Helper class for DivListModel. */
+template<bool UseLinkedList, bool UseDivMask>
+class DivListModelConfiguration;
+
+template<bool ULL, bool UDM>
+class DivListModelConfiguration {
+public:
+ typedef int Exponent;
+ typedef ::Monomial Monomial;
+ typedef Monomial Entry;
+
+ DivListModelConfiguration
+ (size_t varCount,
+ bool sortOnInsert,
+ double rebuildRatio,
+ size_t minRebuild):
+ _varCount(varCount),
+ _sortOnInsert(sortOnInsert),
+ _useAutomaticRebuild((rebuildRatio > 0.0 || minRebuild > 0) && UDM),
+ _rebuildRatio(rebuildRatio),
+ _minRebuild(minRebuild),
+ _expQueryCount(0) {}
+
+ static const bool UseLinkedList = ULL;
+ static const bool UseDivMask = UDM;
+
+ bool getDoAutomaticRebuilds() const {return _useAutomaticRebuild;}
+ double getRebuildRatio() const {return _rebuildRatio;}
+ size_t getRebuildMin() const {return _minRebuild;}
+ bool getSortOnInsert() const {return _sortOnInsert;}
+
+
+ size_t getVarCount() const {return _varCount;}
+
+ Exponent getExponent(const Monomial& monomial, size_t var) const {
+ ++_expQueryCount;
+ ASSERT(var < monomial.size());
+ return monomial[var];
+ }
+
+ bool divides(const Monomial& a, const Monomial& b) const {
+ for (size_t var = 0; var < getVarCount(); ++var)
+ if (getExponent(b, var) < getExponent(a, var))
+ return false;
+ return true;
+ }
+
+ bool isLessThan(const Monomial& a, const Monomial& b) const {
+ for (size_t var = 0; var < getVarCount(); ++var) {
+ if (getExponent(a, var) < getExponent(b, var))
+ return true;
+ if (getExponent(b, var) < getExponent(a, var))
+ return false;
+ }
+ return false;
+ }
+
+ unsigned long long getExpQueryCount() const {return _expQueryCount;}
+
+ private:
+ const size_t _varCount;
+ const bool _sortOnInsert;
+ const bool _useAutomaticRebuild;
+ const double _rebuildRatio;
+ const size_t _minRebuild;
+ mutable unsigned long long _expQueryCount;
+};
+
+template<bool UseLinkedList, bool UseDivMask>
+class DivListModel;
+
+/** An instantiation of the capabilities of DivList. */
+template<bool ULL, bool UDM>
+class DivListModel {
+ private:
+ typedef DivListModelConfiguration<ULL, UDM> C;
+ typedef mathic::DivList<C> Finder;
+ public:
+ typedef typename Finder::iterator iterator;
+ typedef typename Finder::const_iterator const_iterator;
+ typedef typename Finder::Monomial Monomial;
+ typedef typename Finder::Entry Entry;
+
+ DivListModel(size_t varCount,
+ bool minimizeOnInsert,
+ bool moveDivisorToFront,
+ bool sortOnInsert,
+ double rebuildRatio,
+ size_t minRebuild):
+ _finder(C(varCount, sortOnInsert, rebuildRatio, minRebuild)),
+ _minimizeOnInsert(minimizeOnInsert),
+ _moveDivisorToFront(moveDivisorToFront) {
+ ASSERT(!sortOnInsert || !moveDivisorToFront);
+ }
+
+ void insert(const Entry& entry);
+ template<class MultipleOutput>
+ void insert(const Entry& entry, MultipleOutput& removed);
+
+ Entry* findDivisor(const Monomial& monomial) {
+ iterator it = _finder.findDivisorIterator(monomial);
+ if (_moveDivisorToFront && it != _finder.end()) {
+ _finder.moveToFront(it);
+ it = _finder.begin();
+ }
+ return it == end() ? 0 : &*it;
+ }
+ const Entry* findDivisor(const Monomial& monomial) const {
+ return const_cast<DivListModel<ULL, UDM>&>(*this).findDivisor(monomial);
+ }
+
+ template<class DO>
+ void findAllDivisors(const Monomial& monomial, DO& out) {
+ _finder.findAllDivisors(monomial, out);
+ }
+ template<class DO>
+ void findAllDivisors(const Monomial& monomial, DO& out) const {
+ _finder.findAllDivisors(monomial, out);
+ }
+ template<class EO>
+ void forAll(EO& out) {
+ _finder.forAll(out);
+ }
+ template<class EO>
+ void forAll(EO& out) const {
+ _finder.forAll(out);
+ }
+
+ std::string getName() const;
+
+ iterator begin() {return _finder.begin();}
+ const_iterator begin() const {return _finder.begin();}
+ iterator end() {return _finder.end();}
+ const_iterator end() const {return _finder.end();}
+ size_t size() const {return _finder.size();}
+
+ unsigned long long getExpQueryCount() const {
+ return _finder.getConfiguration().getExpQueryCount();
+ }
+
+ private:
+ Finder _finder;
+ const bool _minimizeOnInsert;
+ const bool _moveDivisorToFront;
+};
+
+template<bool ULL, bool UDM>
+inline void DivListModel<ULL, UDM>::insert(const Entry& entry) {
+ if (!_minimizeOnInsert) {
+ _finder.insert(entry);
+ return;
+ }
+ if (findDivisor(entry) != 0)
+ return;
+ bool hasMultiples = _finder.removeMultiples(entry);
+ _finder.insert(entry);
+ if (_moveDivisorToFront && hasMultiples) {
+ iterator it = _finder.end();
+ _finder.moveToFront(--it);
+ }
+}
+
+template<bool ULL, bool UDM>
+template<class MO>
+inline void DivListModel<ULL, UDM>::insert(const Entry& entry, MO& out) {
+ if (!_minimizeOnInsert) {
+ _finder.insert(entry);
+ return;
+ }
+ if (findDivisor(entry) != 0)
+ return;
+ bool hasMultiples = _finder.removeMultiples(entry, out);
+ _finder.insert(entry);
+ if (_moveDivisorToFront && hasMultiples) {
+ iterator it = _finder.end();
+ _finder.moveToFront(--it);
+ }
+}
+
+template<bool ULL, bool UDM>
+inline std::string DivListModel<ULL, UDM>::getName() const {
+ return _finder.getName() +
+ (_minimizeOnInsert ? " remin" : " nomin") +
+ (_moveDivisorToFront ? " toFront" : "");
+}
+
+#endif
diff --git a/src/divsim/KDTreeModel.h b/src/divsim/KDTreeModel.h
new file mode 100755
index 0000000..7b5a44f
--- /dev/null
+++ b/src/divsim/KDTreeModel.h
@@ -0,0 +1,193 @@
+#ifndef K_D_TREE_MODEL_GUARD
+#define K_D_TREE_MODEL_GUARD
+
+#include "Monomial.h"
+#include "mathic/KDTree.h"
+#include <string>
+#include <vector>
+
+template<
+ bool UseDivMask,
+ bool UseTreeDivMask,
+ bool PackedTree,
+ size_t LeafSize,
+ bool AllowRemovals>
+class KDTreeModelConfiguration;
+
+/** Helper class for KDTreeModel. */
+template<bool UDM, bool UTDM, bool PT, size_t LS, bool AR>
+class KDTreeModelConfiguration {
+ public:
+ typedef int Exponent;
+ typedef ::Monomial Monomial;
+ typedef Monomial Entry;
+
+ KDTreeModelConfiguration
+ (size_t varCount,
+ bool sortOnInsert,
+ bool useDivisorCache,
+ double rebuildRatio,
+ size_t minRebuild):
+ _varCount(varCount),
+ _sortOnInsert(sortOnInsert),
+ _useDivisorCache(useDivisorCache),
+ _useAutomaticRebuild((rebuildRatio > 0.0 || minRebuild > 0) && UDM),
+ _rebuildRatio(rebuildRatio),
+ _minRebuild(minRebuild),
+ _expQueryCount(0) {
+ ASSERT(rebuildRatio >= 0);
+ }
+
+ size_t getVarCount() const {return _varCount;}
+ bool getSortOnInsert() const {return _sortOnInsert;}
+
+ Exponent getExponent(const Monomial& monomial, size_t var) const {
+ ++_expQueryCount;
+ ASSERT(var < monomial.size());
+ return monomial[var];
+ }
+
+ NO_PINLINE bool divides(const Monomial& a, const Monomial& b) const {
+ for (size_t var = 0; var < getVarCount(); ++var)
+ if (getExponent(b, var) < getExponent(a, var))
+ return false;
+ return true;
+ }
+
+ bool isLessThan(const Monomial& a, const Monomial& b) const {
+ for (size_t var = 0; var < getVarCount(); ++var) {
+ if (getExponent(a, var) < getExponent(b, var))
+ return true;
+ if (getExponent(b, var) < getExponent(a, var))
+ return false;
+ }
+ return false;
+ }
+
+ size_t getLeafSize() const {return LeafSize;}
+ bool getUseDivisorCache() const {return _useDivisorCache;}
+ bool getDoAutomaticRebuilds() const {return _useAutomaticRebuild;}
+ double getRebuildRatio() const {return _rebuildRatio;}
+ size_t getRebuildMin() const {return _minRebuild;}
+
+ static const bool UseDivMask = UDM;
+ static const bool UseTreeDivMask = UTDM;
+ static const bool PackedTree = PT;
+ static const size_t LeafSize = LS;
+ static const bool AllowRemovals = AR;
+
+ unsigned long long getExpQueryCount() const {return _expQueryCount;}
+
+ private:
+ const size_t _varCount;
+ const bool _sortOnInsert;
+ const bool _useDivisorCache;
+ const bool _useAutomaticRebuild;
+ const double _rebuildRatio;
+ const size_t _minRebuild;
+ mutable unsigned long long _expQueryCount;
+};
+
+/** An instantiation of the capabilities of KDTree. */
+template<
+ bool UseDivMask,
+ bool UseTreeDivMask,
+ bool PackedTree,
+ size_t LeafSize,
+ bool AllowRemovals
+>
+class KDTreeModel {
+ private:
+ typedef KDTreeModelConfiguration
+ <UseDivMask, UseTreeDivMask, PackedTree, LeafSize, AllowRemovals> C;
+ typedef mathic::KDTree<C> Finder;
+ public:
+ typedef typename Finder::Monomial Monomial;
+ typedef typename Finder::Entry Entry;
+
+ KDTreeModel(size_t varCount,
+ bool minimizeOnInsert,
+ bool sortOnInsert,
+ bool useDivisorCache,
+ double rebuildRatio,
+ size_t minRebuild):
+ _finder(C(varCount, sortOnInsert, useDivisorCache, rebuildRatio, minRebuild)),
+ _minimizeOnInsert(minimizeOnInsert) {
+ ASSERT(!UseTreeDivMask || UseDivMask);
+ }
+
+
+ void insert(const Entry& entry);
+ template<class MultipleOutput>
+ void insert(const Entry& entry, MultipleOutput& removed);
+
+ Entry* findDivisor(const Monomial& monomial) {
+ return _finder.findDivisor(monomial);
+ }
+ const Entry* findDivisor(const Monomial& monomial) const {
+ return _finder.findDivisor(monomial);
+ }
+ std::string getName() const;
+
+ template<class DO>
+ void findAllDivisors(const Monomial& monomial, DO& out) {
+ _finder.findAllDivisors(monomial, out);
+ }
+ template<class DO>
+ void findAllDivisors(const Monomial& monomial, DO& out) const {
+ _finder.findAllDivisors(monomial, out);
+ }
+ template<class EO>
+ void forAll(EO& out) {
+ _finder.forAll(out);
+ }
+ template<class EO>
+ void forAll(EO& out) const {
+ _finder.forAll(out);
+ }
+ size_t size() const {return _finder.size();}
+
+ unsigned long long getExpQueryCount() const {
+ return _finder.getConfiguration().getExpQueryCount();
+ }
+
+ class Comparer;
+
+ private:
+ Finder _finder;
+ bool _minimizeOnInsert;
+};
+
+template<bool UDM, bool UTDM, bool PT, size_t LS, bool AR>
+inline void KDTreeModel<UDM, UTDM, PT, LS, AR>::insert(const Entry& entry) {
+ if (!_minimizeOnInsert) {
+ _finder.insert(entry);
+ return;
+ }
+ if (findDivisor(entry) != 0)
+ return;
+ _finder.removeMultiples(entry);
+ _finder.insert(entry);
+}
+
+template<bool UDM, bool UTDM, bool PT, size_t LS, bool AR>
+template<class MultipleOutput>
+inline void KDTreeModel<UDM, UTDM, PT, LS, AR>::
+insert(const Entry& entry, MultipleOutput& removed) {
+ if (!_minimizeOnInsert) {
+ _finder.insert(entry);
+ return;
+ }
+ if (findDivisor(entry) != 0)
+ return;
+ _finder.removeMultiples(entry, removed);
+ _finder.insert(entry);
+}
+
+template<bool UDM, bool UTDM, bool PT, size_t LS, bool AR>
+inline std::string KDTreeModel<UDM, UTDM, PT, LS, AR>::getName() const {
+ return _finder.getName() +
+ (_minimizeOnInsert ? " remin" : " nomin");
+}
+
+#endif
diff --git a/src/divsim/Monomial.h b/src/divsim/Monomial.h
new file mode 100644
index 0000000..45c1c13
--- /dev/null
+++ b/src/divsim/Monomial.h
@@ -0,0 +1,52 @@
+#ifndef MONOMIAL_GUARD
+#define MONOMIAL_GUARD
+
+#include <vector>
+#include <ostream>
+
+class Monomial {
+public:
+ typedef int Exponent;
+
+ Monomial(): _exponents(0) {IF_DEBUG(_size = 0);}
+ Monomial(std::vector<Exponent>& v): _exponents(&v[0]) {
+ IF_DEBUG(_size = v.size());
+ }
+
+ inline Exponent& operator[](size_t index) {
+ ASSERT(index < _size);
+ return _exponents[index];
+ }
+ inline const Exponent& operator[](size_t index) const {
+ ASSERT(index < _size);
+ return _exponents[index];
+ }
+
+ const Exponent* getPointer() const {return _exponents;}
+
+#ifdef DEBUG
+ size_t size() const {return _size;}
+ bool operator==(const Monomial& m) const {return _exponents == m._exponents;}
+ bool operator<(const Monomial& m) const {return _exponents < m._exponents;}
+#endif
+
+private:
+#ifdef DEBUG
+ size_t _size;
+#endif
+ Exponent* _exponents;
+};
+
+inline std::ostream& operator<<(std::ostream& out, const Monomial& monomial) {
+#ifdef DEBUG
+ out << "(Monomial:";
+ for (size_t i = 0; i < monomial.size(); ++i)
+ out << ' ' << monomial[i];
+ out << ')';
+#else
+ out << "(Monomial)";
+#endif
+ return out;
+}
+
+#endif
diff --git a/src/divsim/Simulation.cpp b/src/divsim/Simulation.cpp
new file mode 100755
index 0000000..49ca2f9
--- /dev/null
+++ b/src/divsim/Simulation.cpp
@@ -0,0 +1,62 @@
+#include "stdinc.h"
+#include "Simulation.h"
+
+#include "mathic/ColumnPrinter.h"
+#include <cstdlib>
+#include <algorithm>
+
+namespace {
+ void makeRandom(std::vector<int>& monomial) {
+ for (size_t var = 0; var < monomial.size(); ++var)
+ monomial[var] = rand() % 1000;
+ }
+}
+
+void Simulation::makeStandard
+ (size_t varCount, size_t inserts, size_t queries, bool findAll) {
+ srand(0);
+
+ _findAll = findAll;
+ _varCount = varCount;
+ _events.clear();
+ for (size_t i = 0; i < inserts + queries; ++i) {
+ /*Event event2;
+ event2._type = StateUnknown;
+ _events.push_back(event2);*/
+
+ Event event;
+ event._monomial.resize(varCount);
+ makeRandom(event._monomial);
+ event._type = (i <= inserts ? InsertUnknown : QueryUnknown);
+ _events.push_back(event);
+ }
+}
+
+void Simulation::printData(std::ostream& out) const {
+ std::vector<SimData> sorted(_data);
+ std::sort(sorted.begin(), sorted.end());
+ out << "*** Simulation outcome for "
+ << _repeats << " repeats ***" << std::endl;
+ mic::ColumnPrinter pr;
+ pr.addColumn(true);
+ pr.addColumn(false, " ", "ms");
+ pr.addColumn(false, " ", "eqs");
+ for (std::vector<SimData>::const_iterator it = sorted.begin();
+ it != sorted.end(); ++it) {
+ pr[0] << it->_name << '\n';
+ pr[1] << mic::ColumnPrinter::commafy(it->_mseconds) << '\n';
+ pr[2] << mic::ColumnPrinter::commafy(it->_expQueryCount) << '\n';
+ }
+ pr.print(out);
+}
+
+void Simulation::SimData::print(std::ostream& out) {
+ out << _name
+ << " " << mic::ColumnPrinter::commafy(_mseconds) << " ms"
+ << " " << mic::ColumnPrinter::commafy(_expQueryCount) << " eqs"
+ << '\n';
+}
+
+bool Simulation::SimData::operator<(const SimData& sd) const {
+ return _mseconds < sd._mseconds;
+}
diff --git a/src/divsim/Simulation.h b/src/divsim/Simulation.h
new file mode 100755
index 0000000..75222cb
--- /dev/null
+++ b/src/divsim/Simulation.h
@@ -0,0 +1,310 @@
+#ifndef SIMULATION_GUARD
+#define SIMULATION_GUARD
+
+#include "Monomial.h"
+#include "mathic/Timer.h"
+#include <vector>
+#include <iostream>
+#include <cstdlib>
+#include <algorithm>
+
+class Simulation {
+ public:
+ Simulation(size_t repeats, bool printPartialData):
+ _repeats(repeats), _printPartialData(printPartialData), _simType("none") {}
+
+ void makeStandard(size_t varCount, size_t inserts, size_t queries, bool findAll);
+
+ template<class DivFinder>
+ void run();
+ template<class DivFinder, class Param1>
+ void run(const Param1& param1);
+ template<class DivFinder, class Param1, class Param2>
+ void run(const Param1& param1, const Param2& param2);
+ template<class DivFinder, class Param1, class Param2, class Param3>
+ void run(const Param1& param1, const Param2& param2, const Param3& param3);
+ template<class DivFinder, class P1, class P2, class P3, class P4>
+ void run(const P1& p1, const P2& p2, const P3& param3, const P4& param4);
+ template<class DivFinder, class P1, class P2, class P3, class P4, class P5>
+ void run(const P1& p1, const P2& p2, const P3& param3, const P4& param4,
+ const P5& p5);
+ template<class DivFinder, class P1, class P2, class P3, class P4, class P5,
+ class P6>
+ void run(const P1& p1, const P2& p2, const P3& param3, const P4& param4,
+ const P5& p5, const P6& p6);
+
+ void printData(std::ostream& out) const;
+
+ private:
+ struct SimData {
+ bool operator<(const SimData& sd) const;
+ void print(std::ostream& out);
+
+ std::string _name;
+ unsigned long _mseconds;
+ unsigned long long _expQueryCount;
+ };
+
+ template<class DivFinder>
+ void run(DivFinder& finder);
+
+ enum EventType {
+ InsertUnknown,
+ InsertKnown,
+ QueryNoDivisor,
+ QueryHasDivisor,
+ QueryUnknown,
+ StateUnknown,
+ StateKnown
+ };
+ struct Event {
+ EventType _type;
+ std::vector<int> _monomial;
+ std::vector<const Monomial::Exponent*> _state;
+#ifdef DEBUG
+ std::vector<Monomial> _allMonomials;
+#else
+ size_t _monomialCount;
+#endif
+ };
+ class MonomialStore;
+
+ bool _findAll;
+ std::vector<Event> _events;
+ std::vector<SimData> _data;
+ size_t _varCount;
+ size_t _repeats;
+ bool _printPartialData;
+ std::string _simType;
+};
+
+template<class DivFinder>
+void Simulation::run() {
+ DivFinder finder(_varCount);
+ run(finder);
+}
+
+template<class DivFinder, class Param1>
+void Simulation::run(const Param1& param1) {
+ DivFinder finder(_varCount, param1);
+ run(finder);
+}
+
+template<class DivFinder, class Param1, class Param2>
+void Simulation::run(const Param1& param1, const Param2& param2) {
+ DivFinder finder(_varCount, param1, param2);
+ run(finder);
+}
+
+template<class DivFinder, class Param1, class Param2, class Param3>
+void Simulation::run
+(const Param1& param1, const Param2& param2, const Param3& param3) {
+ DivFinder finder(_varCount, param1, param2, param3);
+ run(finder);
+}
+
+template<class DivFinder, class P1, class P2, class P3, class P4>
+void Simulation::run
+(const P1& param1, const P2& param2, const P3& param3, const P4& param4) {
+ DivFinder finder(_varCount, param1, param2, param3, param4);
+ run(finder);
+}
+
+template<class DivFinder, class P1, class P2, class P3, class P4, class P5>
+void Simulation::run
+(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5) {
+ DivFinder finder(_varCount, p1, p2, p3, p4, p5);
+ run(finder);
+}
+
+template<class DivFinder, class P1, class P2, class P3, class P4,
+class P5, class P6>
+void Simulation::run
+(const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5,
+const P6& p6) {
+ DivFinder finder(_varCount, p1, p2, p3, p4, p5, p6);
+ run(finder);
+}
+
+class Simulation::MonomialStore {
+public:
+ MonomialStore() {clear();}
+ void clear() {
+#ifdef DEBUG
+ _monomials.clear();
+#else
+ _monomialCount = 0;
+#endif
+ }
+
+ void push_back(const Monomial& monomial) {
+ proceed(monomial);
+ }
+ bool proceed(const Monomial& monomial) {
+#ifdef DEBUG
+ _monomials.push_back(monomial);
+#else
+ ++_monomialCount;
+#endif
+ return true;
+ }
+
+ template<class Finder>
+ void checkInsert(Event& e, const Finder& finder) {
+#ifdef DEBUG
+ std::sort(_monomials.begin(), _monomials.end());
+#endif
+
+ if (e._type == InsertUnknown) {
+#ifdef DEBUG
+ e._allMonomials.clear();
+ for (size_t i = 0; i < _monomials.size(); ++i)
+ e._allMonomials.push_back(_monomials[i]);
+#else
+ e._monomialCount = _monomialCount;
+#endif
+ e._type = InsertKnown;
+ } else {
+#ifdef DEBUG
+ ASSERT(_monomials == e._allMonomials);
+#else
+ if (_monomialCount != e._monomialCount) {
+ std::cerr << "Finder \"" << finder.getName() <<
+ "\" found incorrect number of monomials." << std::endl;
+ std::exit(1);
+ }
+#endif
+ }
+ }
+
+ template<class Finder>
+ void checkQuery(Event& e, const Finder& finder) {
+#ifdef DEBUG
+ for (size_t d = 0; d < _monomials.size(); ++d) {
+ for (size_t var = 0; var < e._monomial.size(); ++var) {
+ ASSERT(_monomials[d][var] <= e._monomial[var]);
+ }
+ }
+ std::sort(_monomials.begin(), _monomials.end());
+#endif
+
+ if (e._type == QueryUnknown) {
+ bool noMonomials;
+#ifdef DEBUG
+ e._allMonomials.clear();
+ for (size_t i = 0; i < _monomials.size(); ++i)
+ e._allMonomials.push_back(_monomials[i]);
+ noMonomials = _monomials.empty();
+#else
+ e._monomialCount = _monomialCount;
+ noMonomials = _monomialCount == 0;
+#endif
+ e._type = noMonomials ? QueryNoDivisor : QueryHasDivisor;
+ } else {
+#ifdef DEBUG
+ for (size_t i = 0; i < _monomials.size(); ++i)
+ ASSERT(_monomials[i] == e._allMonomials[i]);
+#else
+ if (_monomialCount != e._monomialCount) {
+ std::cerr << "Finder \"" << finder.getName() <<
+ "\" found incorrect number of monomials." << std::endl;
+ std::exit(1);
+ }
+#endif
+ }
+ }
+
+private:
+#ifdef DEBUG
+ std::vector<Monomial> _monomials;
+#else
+ size_t _monomialCount;
+#endif
+};
+
+struct ForAll {
+public:
+ ForAll(std::vector<const Monomial::Exponent*>& entries): _entries(entries) {}
+ bool proceed(const Monomial& m) {
+ _entries.push_back(m.getPointer());
+ return true;
+ }
+
+private:
+ std::vector<const Monomial::Exponent*>& _entries;
+};
+
+template<class DivFinder>
+void Simulation::run(DivFinder& finder) {
+ mic::Timer timer;
+ std::vector<Monomial> divisors;
+ std::vector<const Monomial::Exponent*> tmp;
+ for (size_t step = 0; step < _repeats; ++step) {
+ for (size_t i = 0; i < _events.size(); ++i) {
+ Event& e = _events[i];
+ if (e._type == InsertKnown || e._type == InsertUnknown) {
+ divisors.clear();
+ MonomialStore store;
+ if (0) {
+ // here to make sure it compiles, also easy to switch to checking this instead.
+ finder.insert(e._monomial);
+ } else
+ finder.insert(e._monomial, store);
+ store.checkInsert(e, finder);
+ } else if (e._type == StateUnknown || e._type == StateKnown) {
+ tmp.clear();
+ ForAll forAll(tmp);
+ finder.forAll(forAll);
+ if (e._type == StateUnknown) {
+ e._type = StateKnown;
+ e._state.swap(tmp);
+ } else {
+ if (e._state != tmp) {
+ std::cerr << "states differ." << std::endl;
+ std::exit(1);
+ }
+ }
+ } else if (!_findAll) {
+ typename DivFinder::Entry* entry = finder.findDivisor(e._monomial);
+ if (entry == 0) {
+ if (e._type == QueryHasDivisor) {
+ std::cerr << "Divisor finder \"" << finder.getName()
+ << "\" failed to find divisor." << std::endl;
+ std::exit(1);
+ }
+ e._type = QueryNoDivisor;
+ } else {
+#ifdef DEBUG
+ for (size_t var = 0; var < _varCount; ++var) {
+ ASSERT((*entry)[var] <= e._monomial[var]);
+ }
+#endif
+ if (e._type == QueryNoDivisor) {
+ std::cerr << "Divisor finder \"" << finder.getName() <<
+ "\" found incorrect divisor." << std::endl;
+ std::exit(1);
+ }
+ e._type = QueryHasDivisor;
+ }
+ } else {
+ ASSERT(_findAll);
+ divisors.clear();
+ MonomialStore store;
+ const_cast<const DivFinder&>(finder) // to test const interface
+ .findAllDivisors(e._monomial, store);
+ store.checkQuery(e, finder);
+ }
+ }
+ }
+
+ SimData data;
+ data._mseconds = (unsigned long)timer.getMilliseconds();
+ data._name = finder.getName();
+ data._expQueryCount = finder.getExpQueryCount();
+ _data.push_back(data);
+ if (_printPartialData)
+ data.print(std::cerr);
+ std::cout << finder.size() << std::endl;
+}
+
+#endif
diff --git a/src/divsim/divMain.cpp b/src/divsim/divMain.cpp
new file mode 100755
index 0000000..8db1e30
--- /dev/null
+++ b/src/divsim/divMain.cpp
@@ -0,0 +1,148 @@
+#include "stdinc.h"
+
+#include "DivListModel.h"
+#include "KDTreeModel.h"
+#include "Simulation.h"
+#include "mathic/Timer.h"
+#include <iostream>
+
+int main() {
+ const size_t repeats = IF_DEBUG(true ? 1 :) 1;
+ Simulation sim(repeats, true);
+ mic::Timer timer;
+ std::cout << "Generating simulation. ";
+
+
+#ifdef DEBUG
+ sim.makeStandard(10, 400, 1000, true);
+#else
+ sim.makeStandard(10, 5000, 2000000, true);
+#endif
+ timer.print(std::cout);
+ std::cout << std::endl;
+
+#ifndef DEBUG
+ sim.run<KDTreeModel<1,1,1,1,1> >(0, 0, 0, 1.0, 1000);
+ sim.run<KDTreeModel<1,1,1,1,0> >(0, 0, 0, 1.0, 1000);
+return 0;
+
+ sim.run<KDTreeModel<0,0,1,2,1> >(1, 0, 0, 0.0, 0); // best tree, no mask
+ sim.run<KDTreeModel<0,0,0,2,1> >(1, 0, 0, 0.0, 0); // best tree, no mask
+
+ sim.run<KDTreeModel<0,0,1,2,1> >(1, 0, 0, 1.0, 1000); // best tree, mask
+ sim.run<KDTreeModel<0,0,0,2,1> >(1, 0, 0, 1.0, 1000); // best tree, mask
+
+ sim.run<DivListModel<0, 0> >(1, 1, 0, 0.5, 500);
+ return 0;
+#endif
+
+
+ /*
+ for (int minimizeOnInsert = 1; minimizeOnInsert <= 1; ++minimizeOnInsert) {
+ for (int order = 0; order <= 2; ++order) {
+ bool moveDivisorToFront = (order == 1);
+ bool sortOnInsert = (order == 2);
+ sim.run<DivListModel<1> >
+ (minimizeOnInsert, moveDivisorToFront, sortOnInsert);
+ sim.run<DivListModel<0> >
+ (minimizeOnInsert, moveDivisorToFront, sortOnInsert);
+ }
+ }
+ //*/
+
+ //sim.run<DivListModel<0, 0> >(1, 0, 1, 0.0, 0); // best array, no mask
+ /*
+ sim.run<DivListModel<0> >(1, 0, 0)
+ sim.run<DivListModel<0> >(1, 1, 0);
+ sim.run<DivListModel<0> >(1, 0, 1);
+ sim.run<DivListModel<1> >(1, 0, 0);
+ sim.run<DivListModel<1> >(1, 1, 0);
+ sim.run<DivListModel<1> >(1, 0, 1);
+ //*/
+
+ sim.run<KDTreeModel<0,0,1,1,0> >(0, 0, 0, 0.0, 0);
+ sim.run<DivListModel<0,0> >(0, 1, 0, 0.5, 500);
+ for (int mini = 0; mini <= 0; ++mini) {
+ for (int sortOnInsert = 0; sortOnInsert <= 1; ++sortOnInsert) {
+ for (int useDivCache = 0; useDivCache <= 1; ++useDivCache) {
+ sim.run<KDTreeModel<1,1,1,1,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+ sim.run<KDTreeModel<1,0,1,1,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+ sim.run<KDTreeModel<0,0,1,1,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+
+ sim.run<KDTreeModel<1,1,1,2,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+ sim.run<KDTreeModel<1,0,1,2,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+ sim.run<KDTreeModel<0,0,1,2,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+
+ sim.run<KDTreeModel<1,1,1,3,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+ sim.run<KDTreeModel<1,0,1,3,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+ sim.run<KDTreeModel<0,0,1,3,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+
+ sim.run<KDTreeModel<1,1,1,20,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+
+ sim.run<KDTreeModel<1,1,0,1,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+ sim.run<KDTreeModel<1,1,0,2,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+ sim.run<KDTreeModel<1,1,0,40,0> >(mini,sortOnInsert,useDivCache, 0.5, 10);
+
+ /*
+ for (size_t leafSize = 5; leafSize <= 15; leafSize += 5)
+ for (size_t start = 0; start <= 0; start += 200)
+ for (double ratio = 0; ratio < 0.1; ratio += 0.2)
+ sim.run<KDTreeModel<0,0> >(leafSize, mini,sortOnInsert,useDivisorCache, ratio, start);
+
+ //*/
+ /*sim.run<KDTreeModel<0> >(8, mini,sortOnInsert,useDivisorCache, 0, 0);
+ sim.run<KDTreeModel<1> >(8, mini,sortOnInsert,useDivisorCache, 0, 0);
+ sim.run<KDTreeModel<0> >(20, mini,sortOnInsert,useDivisorCache, 0, 0);
+ sim.run<KDTreeModel<1> >(20, mini,sortOnInsert,useDivisorCache, 0, 0);
+ sim.run<KDTreeModel<0> >(40, mini,sortOnInsert,useDivisorCache, 0, 0);
+ sim.run<KDTreeModel<1> >(40, mini,sortOnInsert,useDivisorCache, 0, 0);
+ sim.run<KDTreeModel<0> >(60, mini,sortOnInsert,useDivisorCache, 0, 0);
+ sim.run<KDTreeModel<1> >(60, mini,sortOnInsert,useDivisorCache, 0, 0);*/
+
+ /*
+ sim.run<KDTreeModel<1> >(10, mini,sortOnInsert,useDivisorCache, 0.001, 2000);
+ sim.run<KDTreeModel<1> >(10, mini,sortOnInsert,useDivisorCache, 0.001, 4000);
+
+ sim.run<KDTreeModel<0> >(10, mini,sortOnInsert,useDivisorCache, 0.001, 6000);
+ sim.run<KDTreeModel<1> >(10, mini,sortOnInsert,useDivisorCache, 0.001, 6000);
+
+ sim.run<KDTreeModel<1> >(10, mini,sortOnInsert,useDivisorCache, 0.001, 8000);
+ sim.run<KDTreeModel<1> >(10, mini,sortOnInsert,useDivisorCache, 0.001, 10000);*/
+ //sim.run<KDTreeModel>(10, mini,sortOnInsert,useDivisorCache, 4, 2000);
+ //sim.run<KDTreeModel>(20, mini,sortOnInsert,useDivisorCache, 0.75, 2000);
+ //sim.run<KDTreeModel>(8, mini,sortOnInsert,useDivisorCache, 0.75, 2000);
+ }
+ }
+ }
+ //*/
+ /*
+ for (int mini = 1; mini <= 1; ++mini) {
+ for (int noneFrontSort = 0; noneFrontSort <= 2; ++noneFrontSort) {
+ bool tof = (noneFrontSort == 1);
+ bool sort = (noneFrontSort == 2);
+
+ for (double ratio = 0.5; ratio < 0.51; ratio += 0.1)
+ for (size_t start = 500; start <= 500; start += 100)
+ sim.run<DivListModel<1, 1> >(mini, tof, sort, ratio, start);
+ }
+ }
+ //*/
+
+ /* best for single query from best to worst
+ sim.run<KDTreeModel<1,1> >(40, 1, 0, 0, 1.0, 1000); // best tree, mask
+ sim.run<KDTreeModel<0,0> >(15, 1, 0, 0, 0.0, 0); // best tree, no mask
+ sim.run<DivListModel<0, 1> >(1, 1, 0, 0.5, 500); // best array, mask
+ sim.run<DivListModel<1, 1> >(1, 1, 0, 0.5, 500); // should be best linked, mask
+ sim.run<DivListModel<0, 0> >(1, 0, 1, 0.0, 0); // best array, no mask
+ sim.run<DivListModel<1, 0> >(1, 0, 1, 0.0, 0); // best linked, no mask
+ //*/
+
+ /* base div lists
+ sim.run<DivListModel<0, 0> >(1, 0, 0, 0.0, 0); // base array
+ sim.run<DivListModel<1, 0> >(1, 0, 0, 0.0, 0); // base linked
+ //*/
+
+ std::cout << "\n\n";
+ sim.printData(std::cout);
+ return 0;
+}
diff --git a/src/divsim/divMain.h b/src/divsim/divMain.h
new file mode 100755
index 0000000..c466ef7
--- /dev/null
+++ b/src/divsim/divMain.h
@@ -0,0 +1,6 @@
+#ifndef MATHIC_DIV_MAIN_GUARD
+#define MATHIC_DIV_MAIN_GUARD
+
+int main();
+
+#endif
diff --git a/src/divsim/stdinc.h b/src/divsim/stdinc.h
new file mode 100755
index 0000000..d03df67
--- /dev/null
+++ b/src/divsim/stdinc.h
@@ -0,0 +1,57 @@
+#ifdef STDINC_GUARD
+#error stdinc.h included twice
+#endif
+#define STDINC_GUARD
+
+#ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++.
+#pragma warning (push, 1) // Reduce warning level for GMP headers.
+#endif
+
+#ifdef PROFILE
+#define NO_PINLINE NO_INLINE
+#else
+#define NO_PINLINE
+#endif
+
+#ifndef _MSC_VER
+#define NO_INLINE __attribute__ ((noinline))
+#endif
+
+#ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++.
+#define NO_INLINE __declspec(noinline)
+#pragma warning (pop) // Go back to previous warning level.
+#pragma warning (disable: 4996) // std::copy is flagged as dangerous.
+#pragma warning (disable: 4290) // VC++ ignores throw () specification.
+#pragma warning (disable: 4127) // Warns about using "while (true)".
+#pragma warning (disable: 4100) // Warns about unused parameters.
+#pragma warning (disable: 4800) // Warns on int to bool conversion.
+#pragma warning (disable: 4146) // Warns on unary minus on unsigned (bit trick)
+
+// This warning warns about using the this pointer in base member
+// initializer lists. This is a pretty good warning as that can
+// obviously easily go wrong, but it is pretty useful to do as well,
+// so the warning is turned off.
+#pragma warning (disable: 4355)
+
+#ifdef _DEBUG
+#define DEBUG
+#endif
+
+#endif
+
+#include <cstddef>
+#include <memory>
+
+#ifdef DEBUG
+#include <iostream> // Useful for debugging.
+#define PRINT
+#include <cassert>
+#define ASSERT(X) assert(X);
+#define IF_DEBUG(X) X
+#else
+#define ASSERT(X)
+#define IF_DEBUG(X)
+#endif
+
+static const size_t BitsPerByte = 8;
+static const size_t MemoryAlignment = sizeof(void*);
diff --git a/src/mathic.h b/src/mathic.h
new file mode 100755
index 0000000..4d46862
--- /dev/null
+++ b/src/mathic.h
@@ -0,0 +1,27 @@
+// Include this file to pull in all external MemTailor files
+
+// utilities
+#include "../../src/Timer.h"
+#include "../../src/ColumnPrinter.h"
+#include "../../src/ElementDeleter.h"
+#include "../../src/error.h"
+
+// divisor query data structures
+#include "../../src/DivList.h"
+#include "../../src/KDTree.h"
+
+// priority queue data structures
+#include "../../src/TourTree.h"
+#include "../../src/StlSet.h"
+#include "../../src/Heap.h"
+#include "../../src/Geobucket.h"
+
+// CLI package
+#include "../../src/Action.h"
+#include "../../src/BoolParameter.h"
+#include "../../src/CliParameter.h"
+#include "../../src/CliParser.h"
+#include "../../src/HelpAction.h"
+#include "../../src/IntegerParameter.h"
+#include "../../src/StringParameter.h"
+#include "../../src/display.h"
diff --git a/src/mathic/Action.cpp b/src/mathic/Action.cpp
new file mode 100755
index 0000000..a0e2488
--- /dev/null
+++ b/src/mathic/Action.cpp
@@ -0,0 +1,17 @@
+#include "Action.h"
+#include "error.h"
+
+namespace mathic {
+ Action::~Action() {
+ }
+
+ void Action::directOptions(
+ std::vector<std::string> tokens,
+ CliParser& parser
+ ) {
+ if (!tokens.empty()) {
+ reportError("Expected a dash (-) to indicate an option when reading \"" +
+ tokens.front() + "\".");
+ }
+ }
+}
diff --git a/src/mathic/Action.h b/src/mathic/Action.h
new file mode 100755
index 0000000..2266bc1
--- /dev/null
+++ b/src/mathic/Action.h
@@ -0,0 +1,46 @@
+#ifndef MATHIC_ACTION_GUARD
+#define MATHIC_ACTION_GUARD
+
+#include "stdinc.h"
+#include <string>
+#include <vector>
+
+namespace mathic {
+ class CliParameter;
+ class CliParser;
+
+ class Action {
+ public:
+ virtual ~Action();
+
+ // Called with tokens that precede any option of the
+ // form -option. The default is to give an error saying
+ // that a dash was expected if tokens is not empty.
+ virtual void directOptions
+ (std::vector<std::string> tokens, CliParser& parser);
+
+ // Do what it is this action does.
+ virtual void performAction() = 0;
+
+ // ***************************************
+ // **** Information provided by each Action
+
+ // The name of the action.
+ virtual const char* name() const = 0;
+
+ // More detailed explanation of what the action does.
+ virtual const char* description() const = 0;
+
+ // One-line summary of the description.
+ virtual const char* shortDescription() const = 0;
+
+ // Append the parameters for this action to the passed-in container.
+ // Do not clear the passed-in container.
+ virtual void pushBackParameters(std::vector<CliParameter*>& parameters) = 0;
+
+ // Return true if this class is HelpAction.
+ virtual bool isHelpAction() const {return false;}
+ };
+}
+
+#endif
diff --git a/src/mathic/BinaryKDTree.h b/src/mathic/BinaryKDTree.h
new file mode 100755
index 0000000..9d88307
--- /dev/null
+++ b/src/mathic/BinaryKDTree.h
@@ -0,0 +1,780 @@
+#ifndef MATHIC_BINARY_K_D_TRExtEntry_GUARD
+#define MATHIC_BINARY_K_D_TRExtEntry_GUARD
+
+#include "stdinc.h"
+#include "DivMask.h"
+#include "KDEntryArray.h"
+#include <memtailor.h>
+#include <ostream>
+
+namespace mathic {
+ template<class C>
+ class BinaryKDTree {
+ public:
+ typedef typename C::Monomial Monomial;
+ typedef typename C::Entry Entry;
+ typedef typename C::Exponent Exponent;
+ typedef typename DivMask::Extender<Entry, C::UseDivMask> ExtEntry;
+ typedef typename DivMask::Extender<const Monomial&,C::UseDivMask> ExtMonoRef;
+ typedef typename DivMask::Calculator<C> DivMaskCalculator;
+
+ struct ExpOrder {
+ ExpOrder(size_t var, const C& conf): _var(var), _conf(conf) {}
+ bool operator()(const ExtEntry& a, const ExtEntry& b) const {
+ return _conf.getExponent(a.get(), _var) < _conf.getExponent(b.get(), _var);
+ }
+ private:
+ const size_t _var;
+ const C& _conf;
+ };
+
+ private:
+ /** A helper class for KDTree. A node in the tree. The ExtEntry
+ comes from the KdTree. */
+ class KDTreeNode;
+
+ /** A helper class for KDTree. An interior node in the tree. The ExtEntry
+ comes from the KdTree. @todo: rename to KDTreeInternal. */
+ class KDTreeInterior;
+
+ /** A helper class for KDTree. Represents a leaf in the tree. Leaves
+ hold the monomials. The Configuration is as for KdTree. The ExtEntry
+ comes from the KdTree. */
+ class KDTreeLeaf;
+
+ typedef KDTreeNode Node;
+ typedef KDTreeInterior Interior;
+ typedef KDTreeLeaf Leaf;
+ typedef C Configuration;
+ static const bool UseDivMask = C::UseDivMask;
+
+ class KDTreeNode {
+ public:
+ bool isLeaf() const {return _isLeaf;}
+ const Leaf& asLeaf() const {
+ MATHIC_ASSERT(isLeaf());
+ return static_cast<const Leaf&>(*this);
+ }
+ Leaf& asLeaf() {
+ MATHIC_ASSERT(isLeaf());
+ return static_cast<Leaf&>(*this);
+ }
+
+ bool isInterior() const {return !isLeaf();}
+ const Interior& asInterior() const {
+ MATHIC_ASSERT(isInterior());
+ return static_cast<Interior&>(*this);
+ }
+ Interior& asInterior() {
+ MATHIC_ASSERT(isInterior());
+ return static_cast<Interior&>(*this);
+ }
+
+ protected:
+ KDTreeNode(bool leaf): _isLeaf(leaf) {}
+
+ private:
+ KDTreeNode(const KDTreeNode&); // unavailable
+ void operator=(const KDTreeNode&); // unavailable
+
+ class SplitEqualOrLess;
+ const bool _isLeaf;
+ };
+
+ class KDTreeInterior : public KDTreeNode,
+ public mathic::DivMask::HasDivMask<C::UseTreeDivMask> {
+ public:
+ typedef typename C::Exponent Exponent;
+ typedef KDTreeInterior Interior;
+ typedef KDTreeLeaf Leaf;
+ typedef KDTreeNode Node;
+
+ KDTreeInterior
+ (Node& equalOrLess,
+ Node& strictlyGreater,
+ size_t var,
+ Exponent exponent):
+ Node(false),
+ _equalOrLess(&equalOrLess),
+ _strictlyGreater(&strictlyGreater),
+ _var(var),
+ _exponent(exponent) {
+ }
+ KDTreeInterior
+ (size_t var,
+ Exponent exponent):
+ Node(false),
+ _equalOrLess(0),
+ _strictlyGreater(0),
+ _var(var),
+ _exponent(exponent) {
+ }
+ size_t getVar() const {return _var;}
+ Exponent getExponent() const {return _exponent;}
+
+ Node& getEqualOrLess() {return *_equalOrLess;}
+ const Node& getEqualOrLess() const {return *_equalOrLess;}
+ void setEqualOrLess(Node* equalOrLess) {_equalOrLess = equalOrLess;}
+
+ Node& getStrictlyGreater() {return *_strictlyGreater;}
+ const Node& getStrictlyGreater() const {return *_strictlyGreater;}
+ void setStrictlyGreater(Node* strictlyGreater) {
+ _strictlyGreater = strictlyGreater;
+ }
+
+ Node& getChildFor(const ExtEntry& entry, const C& conf) {
+ if (getExponent() < conf.getExponent(entry.get(), getVar()))
+ return getStrictlyGreater();
+ else
+ return getEqualOrLess();
+ }
+
+ using DivMask::HasDivMask<C::UseTreeDivMask>::updateToLowerBound;
+ void updateToLowerBound(Node& node) {
+ if (!C::UseTreeDivMask)
+ return;
+ if (node.isLeaf())
+ DivMask::HasDivMask<C::UseTreeDivMask>::
+ updateToLowerBound(node.asLeaf().entries());
+ else
+ DivMask::HasDivMask<C::UseTreeDivMask>::
+ updateToLowerBound(node.asInterior());
+ }
+
+ private:
+ Node* _equalOrLess;
+ Node* _strictlyGreater;
+ size_t _var;
+ Exponent _exponent;
+ };
+
+
+ class KDTreeLeaf : public KDTreeNode {
+ typedef KDTreeInterior Interior;
+ typedef KDTreeLeaf Leaf;
+ typedef KDTreeNode Node;
+ public:
+ typedef typename C::Monomial Monomial;
+ typedef ExtEntry* iterator;
+ typedef const ExtEntry* const_iterator;
+ typedef const ExtEntry& const_reference;
+ typedef ExtEntry value_type;
+ typedef DivMask::Calculator<C> DivMaskCalculator;
+
+ KDTreeLeaf(memt::Arena& arena, const C& conf);
+
+ /** Copies Entry's in [begin, end) into the new leaf after
+ calculating div mask if using those. */
+ template<class Iter>
+ KDTreeLeaf(Iter begin, Iter end, memt::Arena& arena,
+ const DivMaskCalculator& calc, const C& conf);
+
+ /** Copies ExtEntry's [begin, end) into the new leaf. */
+ template<class Iter>
+ KDTreeLeaf(Iter begin, Iter end, memt::Arena& arena, const C& conf);
+
+ mathic::KDEntryArray<C, ExtEntry>& entries() {return _entries;}
+ const KDEntryArray<C, ExtEntry>& entries() const {return _entries;}
+
+ /** When this node is full, call this to insert an element. It
+ splits the elements in this noe into two leaves and returns
+ a new interior node that is the parent of them. */
+ Interior& splitInsert(const ExtEntry& entry, Interior* parent,
+ memt::Arena& arena, const C& conf);
+
+ private:
+ KDEntryArray<C, ExtEntry> _entries;
+ };
+
+ public:
+ typedef typename Leaf::iterator LeafIt;
+
+ public:
+ BinaryKDTree(const C& configuration);
+ ~BinaryKDTree();
+
+ template<class MultipleOutput>
+ size_t removeMultiples(const ExtMonoRef& monomial, MultipleOutput& out);
+
+ bool removeElement(const Monomial& monomial);
+
+ void insert(const ExtEntry& entry);
+
+ template<class Iter>
+ void reset(Iter begin, Iter end, const DivMaskCalculator& calc);
+
+ inline Entry* findDivisor(const ExtMonoRef& monomial);
+
+ template<class DivisorOutput>
+ inline void findAllDivisors
+ (const ExtMonoRef& monomial, DivisorOutput& out);
+
+ template<class Output>
+ inline void findAllMultiples
+ (const ExtMonoRef& monomial, Output& out);
+
+ template<class EntryOutput>
+ void forAll(EntryOutput& out);
+
+ void clear();
+
+ size_t getMemoryUse() const;
+
+ C& getConfiguration() {return _conf;}
+
+ void print(std::ostream& out) const;
+
+#ifdef MATHIC_DEBUG
+ bool debugIsValid() const;
+#endif
+
+ private:
+ BinaryKDTree(const BinaryKDTree<C>&); // unavailable
+ void operator=(const BinaryKDTree<C>&); // unavailable
+
+ template<class Iter>
+ struct InsertTodo {
+ Iter begin;
+ Iter end;
+ Interior* parent;
+ };
+
+ memt::Arena _arena; // Everything permanent allocated from here.
+ C _conf; // User supplied configuration.
+ mutable std::vector<Node*> _tmp; // For navigating the tree.
+ Node* _root; // Root of the tree. Can be null!
+ };
+
+ template<class C>
+ BinaryKDTree<C>::BinaryKDTree(const C& configuration):
+ _conf(configuration), _root(0) {
+ MATHIC_ASSERT(C::LeafSize > 0);
+ MATHIC_ASSERT(debugIsValid());
+ }
+
+ template<class C>
+ BinaryKDTree<C>::~BinaryKDTree() {
+ clear();
+ }
+
+ template<class C>
+ template<class MO>
+ size_t BinaryKDTree<C>::removeMultiples(const ExtMonoRef& extMonomial, MO& out) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return 0;
+ size_t removedCount = 0;
+ Node* node = _root;
+ while (true) {
+ while (node->isInterior()) {
+ Interior& interior = node->asInterior();
+ if (!(interior.getExponent() <
+ _conf.getExponent(extMonomial.get(), interior.getVar())))
+ _tmp.push_back(&interior.getEqualOrLess());
+ node = &interior.getStrictlyGreater();
+ }
+ MATHIC_ASSERT(node->isLeaf());
+ removedCount += node->asLeaf().entries().removeMultiples(extMonomial, out, _conf);
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ MATHIC_ASSERT(debugIsValid());
+ return removedCount;
+ }
+
+ template<class C>
+ bool BinaryKDTree<C>::removeElement(const Monomial& monomial) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return 0;
+ Node* node = _root;
+
+ while (node->isInterior())
+ node = node->asInterior().getChildFor(monomial, _conf);
+ const bool value = node->asLeaf().removeElement(monomial);
+ MATHIC_ASSERT(debugIsValid());
+ return value;
+ }
+
+ template<class C>
+ void BinaryKDTree<C>::insert(const ExtEntry& extEntry) {
+ Interior* parent = 0;
+ if (_root == 0)
+ _root = new (_arena.allocObjectNoCon<Leaf>()) Leaf(_arena, _conf);
+ Node* node = _root;
+ while (node->isInterior()) {
+ parent = &node->asInterior();
+ if (C::UseTreeDivMask)
+ parent->updateToLowerBound(extEntry);
+ node = &parent->getChildFor(extEntry, _conf);
+ }
+ Leaf* leaf = &node->asLeaf();
+
+ MATHIC_ASSERT(leaf->entries().size() <= C::LeafSize);
+ if (leaf->entries().size() == C::LeafSize) {
+ Interior& interior = leaf->splitInsert(extEntry, parent, _arena, _conf);
+ if (parent == 0) {
+ ASSERT(leaf == _root);
+ _root = &interior;
+ }
+ } else {
+ MATHIC_ASSERT(leaf->entries().size() < C::LeafSize);
+ leaf->entries().insert(extEntry, _conf);
+ MATHIC_ASSERT(debugIsValid());
+ }
+ }
+
+ template<class C>
+ template<class Iter>
+ void BinaryKDTree<C>::reset(Iter insertBegin, Iter insertEnd, const DivMaskCalculator& calc) {
+ clear();
+ if (insertBegin == insertEnd)
+ return;
+
+ typedef InsertTodo<Iter> Task;
+ typedef std::vector<Task> TaskCont;
+ TaskCont todo;
+
+ Interior* parent = 0;
+ bool isEqualOrLessChild = false;
+ while (true) {
+ Node* node = 0;
+ const size_t insertCount = std::distance(insertBegin, insertEnd);
+ const bool isLeaf = (insertCount <= C::LeafSize);
+ if (isLeaf)
+ node = new (_arena.allocObjectNoCon<Leaf>())
+ Leaf(insertBegin, insertEnd, _arena, calc, _conf);
+ else {
+ size_t var =
+ (parent == 0 ? static_cast<size_t>(-1) : parent->getVar());
+
+ Exponent exp;
+ Iter middle = KDEntryArray<C, ExtEntry>::
+ split(insertBegin, insertEnd, var, exp, _conf);
+ Interior* interior = new (_arena.allocObjectNoCon<Interior>())
+ Interior(var, exp);
+
+ MATHIC_ASSERT(middle != insertBegin && middle != insertEnd);
+ // push strictly-greater on todo
+ Task task;
+ task.begin = middle;
+ task.end = insertEnd;
+ task.parent = interior;
+ todo.push_back(task);
+ // set up equal-or-less
+ insertEnd = middle;
+ node = interior;
+ }
+
+ if (parent == 0) {
+ ASSERT(_root == 0);
+ _root = node;
+ } else if (isEqualOrLessChild)
+ parent->setEqualOrLess(node);
+ else
+ parent->setStrictlyGreater(node);
+
+ if (isLeaf) {
+ // grab next item from todo
+ if (todo.empty())
+ break;
+ Task task = todo.back();
+ todo.pop_back();
+ insertBegin = task.begin;
+ insertEnd = task.end;
+ parent = task.parent;
+ // only strictlyGreater goes on todo
+ isEqualOrLessChild = false;
+ } else {
+ isEqualOrLessChild = true;
+ parent = &node->asInterior();
+ // continue with equal-or-less as next item
+ }
+ }
+ ASSERT(_root != 0);
+
+ if (C::UseTreeDivMask) {
+ // record nodes in tree using breadth first search
+ typedef std::vector<Interior*> NodeCont;
+ NodeCont nodes;
+ if (_root->isInterior())
+ nodes.push_back(&_root->asInterior());
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ Interior* node = nodes[i];
+ if (node->getEqualOrLess().isInterior())
+ nodes.push_back(&node->getEqualOrLess().asInterior());
+ if (node->getStrictlyGreater().isInterior())
+ nodes.push_back(&node->getStrictlyGreater().asInterior());
+ }
+ // compute div masks in reverse order of breath first search
+ typename NodeCont::reverse_iterator it = nodes.rbegin();
+ typename NodeCont::reverse_iterator end = nodes.rend();
+ for (; it != end; ++it) {
+ Interior* node = *it;
+ node->updateToLowerBound(node->getEqualOrLess());
+ node->updateToLowerBound(node->getStrictlyGreater());
+ }
+ }
+ MATHIC_ASSERT(debugIsValid());
+ }
+
+ template<class C>
+ typename BinaryKDTree<C>::Entry* BinaryKDTree<C>::findDivisor
+ (const ExtMonoRef& extMonomial) {
+
+ MATHIC_ASSERT(debugIsValid());
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return 0;
+ Node* node = _root;
+ while (true) {
+ while (node->isInterior()) {
+ Interior& interior = node->asInterior();
+ if (C::UseTreeDivMask &&
+ !interior.getDivMask().canDivide(extMonomial.getDivMask()))
+ goto next;
+
+ if (interior.getExponent() <
+ _conf.getExponent(extMonomial.get(), interior.getVar()))
+ _tmp.push_back(&interior.getStrictlyGreater());
+ node = &interior.getEqualOrLess();
+ }
+
+ {
+ MATHIC_ASSERT(node->isLeaf());
+ Leaf& leaf = node->asLeaf();
+ LeafIt leafIt = leaf.entries().findDivisor(extMonomial, _conf);
+ if (leafIt != leaf.entries().end()) {
+ MATHIC_ASSERT(_conf.divides(leafIt->get(), extMonomial.get()));
+ _tmp.clear();
+ return &leafIt->get();
+ }
+ }
+ next:
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ return 0;
+ }
+
+ template<class C>
+ template<class DO>
+ void BinaryKDTree<C>::findAllDivisors(const ExtMonoRef& extMonomial, DO& output) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return;
+ Node* node = _root;
+ while (true) {
+ while (node->isInterior()) {
+ Interior& interior = node->asInterior();
+ if (C::UseTreeDivMask &&
+ !interior.getDivMask().canDivide(extMonomial.getDivMask()))
+ goto next;
+ if (interior.getExponent() <
+ _conf.getExponent(extMonomial.get(), interior.getVar()))
+ _tmp.push_back(&interior.getStrictlyGreater());
+ node = &interior.getEqualOrLess();
+ }
+ MATHIC_ASSERT(node->isLeaf());
+ {
+ Leaf& leaf = node->asLeaf();
+ if (!leaf.entries().findAllDivisors(extMonomial, output, _conf)) {
+ _tmp.clear();
+ break;
+ }
+ }
+next:
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ }
+
+ template<class C>
+ template<class DO>
+ void BinaryKDTree<C>::findAllMultiples(const ExtMonoRef& extMonomial, DO& output) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return;
+ Node* node = _root;
+ while (true) {
+ while (node->isInterior()) {
+ Interior& interior = node->asInterior();
+ if (!(interior.getExponent() <
+ _conf.getExponent(extMonomial.get(), interior.getVar())))
+ _tmp.push_back(&interior.getEqualOrLess());
+ node = &interior.getStrictlyGreater();
+ }
+ MATHIC_ASSERT(node->isLeaf());
+ {
+ Leaf& leaf = node->asLeaf();
+ if (!leaf.entries().findAllMultiples(extMonomial, output, _conf)) {
+ _tmp.clear();
+ break;
+ }
+ }
+next:
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ }
+
+ template<class C>
+ template<class EO>
+ void BinaryKDTree<C>::forAll(EO& output) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return;
+ Node* node = _root;
+ while (true) {
+ while (node->isInterior()) {
+ Interior& interior = node->asInterior();
+ _tmp.push_back(&interior.getStrictlyGreater());
+ node = &interior.getEqualOrLess();
+ }
+ MATHIC_ASSERT(node->isLeaf());
+ Leaf& leaf = node->asLeaf();
+ if (!leaf.entries().forAll(output)) {
+ _tmp.clear();
+ break;
+ }
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ }
+
+ template<class C>
+ void BinaryKDTree<C>::clear() {
+ MATHIC_ASSERT(_tmp.empty());
+ // Call Entry destructors
+ if (_root != 0)
+ _tmp.push_back(_root);
+ while (!_tmp.empty()) {
+ Node* node = _tmp.back();
+ _tmp.pop_back();
+ while (node->isInterior()) {
+ _tmp.push_back(&node->asInterior().getStrictlyGreater());
+ node = &node->asInterior().getEqualOrLess();
+ }
+ MATHIC_ASSERT(node->isLeaf());
+ node->asLeaf().entries().clear();
+ }
+ _arena.freeAllAllocs();
+ _root = 0;
+ }
+
+ template<class C>
+ size_t BinaryKDTree<C>::getMemoryUse() const {
+ size_t sum = _arena.getMemoryUse();
+ sum += _tmp.capacity() * sizeof(_tmp.front());
+ return sum;
+ }
+
+ template<class C>
+ void BinaryKDTree<C>::print(std::ostream& out) const {
+ out << "<<<<<<<< BinaryKDTree >>>>>>>>\n";
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root != 0) {
+ Node* node = _root;
+ while (true) {
+ if (node->isInterior()) {
+ Interior& interior = node->asInterior();
+ out << "**** Interior Node " << &interior << '\n';
+ out << "Split on " << interior.getVar() <<
+ '^' << interior.getExponent() << '\n';
+ out << "Child <=: " << &interior.getEqualOrLess() << '\n';
+ out << "Child > : " << &interior.getStrictlyGreater() << '\n';
+ out << '\n';
+ _tmp.push_back(&interior.getEqualOrLess());
+ _tmp.push_back(&interior.getStrictlyGreater());
+ } else {
+ Leaf& leaf = node->asLeaf();
+ out << "**** Leaf Node " << &leaf << '\n';
+ for (size_t i = 0; i < leaf.entries().size(); ++i) {
+ out << "Entry " << (i + 1) << ": "
+ << leaf.entries().begin()[i].get() << '\n';
+ }
+ out << '\n';
+ }
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ }
+ }
+
+#ifdef MATHIC_DEBUG
+ template<class C>
+ bool BinaryKDTree<C>::debugIsValid() const {
+ MATHIC_ASSERT(_tmp.empty());
+ MATHIC_ASSERT(!_conf.getDoAutomaticRebuilds() || _conf.getRebuildRatio() > 0);
+
+ if (_root == 0)
+ return true;
+
+ // record all nodes
+ std::vector<Node*> nodes;
+ nodes.push_back(_root);
+ size_t sizeSum = 0;
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ Node* node = nodes[i];
+ if (node->isInterior()) {
+ MATHIC_ASSERT(node->asInterior().getVar() < _conf.getVarCount());
+ nodes.push_back(&node->asInterior().getStrictlyGreater());
+ nodes.push_back(&node->asInterior().getEqualOrLess());
+ } else
+ sizeSum += node->asLeaf().entries().size();
+ }
+
+ // check the recorded nodes
+ MATHIC_ASSERT(_tmp.empty());
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ Node* nodei = nodes[i];
+ if (nodei->isLeaf()) {
+ ASSERT(nodei->asLeaf().entries().debugIsValid());
+ continue;
+ }
+ Interior& interior = nodei->asInterior();
+ size_t var = interior.getVar();
+ Exponent exp = interior.getExponent();
+
+ ASSERT(_tmp.empty());
+ // check equal or less than sub tree
+ _tmp.push_back(&interior.getEqualOrLess());
+ while (!_tmp.empty()) {
+ Node* node = _tmp.back();
+ _tmp.pop_back();
+ if (C::UseTreeDivMask) {
+ if (node->isInterior())
+ MATHIC_ASSERT(interior.getDivMask().canDivide(node->asInterior().getDivMask()));
+ else
+ MATHIC_ASSERT(interior.getDivMask().canDivide(node->asLeaf().entries().getDivMask()));
+ }
+ if (node->isInterior()) {
+ _tmp.push_back(&node->asInterior().getStrictlyGreater());
+ _tmp.push_back(&node->asInterior().getEqualOrLess());
+ } else {
+ MATHIC_ASSERT(node->asLeaf().entries().allLessThanOrEqualTo(var, exp, _conf));
+ }
+ }
+
+ // check strictly greater
+ _tmp.push_back(&interior.getStrictlyGreater());
+ while (!_tmp.empty()) {
+ Node* node = _tmp.back();
+ _tmp.pop_back();
+ if (C::UseTreeDivMask) {
+ if (node->isInterior())
+ MATHIC_ASSERT(interior.getDivMask().canDivide(node->asInterior().getDivMask()));
+ else
+ MATHIC_ASSERT(interior.getDivMask().canDivide(node->asLeaf().entries().getDivMask()));
+ }
+ if (node->isInterior()) {
+ _tmp.push_back(&node->asInterior().getStrictlyGreater());
+ _tmp.push_back(&node->asInterior().getEqualOrLess());
+ } else {
+ MATHIC_ASSERT(node->asLeaf().entries().allStrictlyGreaterThan(var, exp, _conf));
+ }
+ }
+ }
+ return true;
+ }
+#endif
+
+ template<class C>
+ BinaryKDTree<C>::KDTreeLeaf::KDTreeLeaf(memt::Arena& arena, const C& conf):
+ Node(true), _entries(arena, conf) {}
+
+ template<class C>
+ template<class Iter>
+ BinaryKDTree<C>::KDTreeLeaf::KDTreeLeaf(
+ Iter begin,
+ Iter end,
+ memt::Arena& arena,
+ const DivMaskCalculator& calc,
+ const C& conf):
+ Node(true), _entries(begin, end, arena, calc, conf) {}
+
+ template<class C>
+ template<class Iter>
+ BinaryKDTree<C>::KDTreeLeaf::KDTreeLeaf(
+ Iter begin,
+ Iter end,
+ memt::Arena& arena,
+ const C& conf):
+ Node(true), _entries(begin, end, arena, conf) {}
+
+ template<class C>
+ class BinaryKDTree<C>::KDTreeNode::SplitEqualOrLess {
+ public:
+ typedef typename C::Exponent Exponent;
+ typedef typename C::Entry Entry;
+ SplitEqualOrLess(size_t var, const Exponent& exp, const C& conf):
+ _var(var), _exp(exp), _conf(conf) {}
+ bool operator()(const Entry& entry) const {
+ return !(_exp < _conf.getExponent(entry, _var));
+ }
+ private:
+ size_t _var;
+ const Exponent& _exp;
+ const C& _conf;
+ };
+
+ template<class C>
+ typename BinaryKDTree<C>::KDTreeInterior&
+ BinaryKDTree<C>::KDTreeLeaf::splitInsert(const ExtEntry& extEntry, Interior* parent, memt::Arena& arena, const C& conf) {
+ MATHIC_ASSERT(conf.getVarCount() > 0);
+ MATHIC_ASSERT(entries().size() > 0);
+ size_t var = (parent == 0 ? static_cast<size_t>(-1) : parent->getVar());
+ typename C::Exponent exp;
+
+ iterator middle = KDEntryArray<C, ExtEntry>::split
+ (entries().begin(), entries().end(), var, exp, conf, &extEntry);
+ Leaf& other = *new (arena.allocObjectNoCon<Leaf>()) Leaf(middle, entries().end(), arena, conf);
+ while (middle != entries().end())
+ entries().pop_back();
+ if (conf.getSortOnInsert())
+ std::sort(entries().begin(), entries().end(), Comparer<C>(conf));
+
+ Interior& interior = *new (arena.allocObjectNoCon<Interior>())
+ Interior(*this, other, var, exp);
+ if (C::UseTreeDivMask) {
+ entries().recalculateTreeDivMask();
+ interior.updateToLowerBound(entries());
+ interior.updateToLowerBound(other.entries());
+ }
+ if (parent != 0) {
+ if (&parent->getEqualOrLess() == this)
+ parent->setEqualOrLess(&interior);
+ else {
+ MATHIC_ASSERT(&parent->getStrictlyGreater() == this);
+ parent->setStrictlyGreater(&interior);
+ }
+ }
+
+ interior.updateToLowerBound(extEntry);
+ Leaf* insertLeaf = &interior.getChildFor(extEntry, conf).asLeaf();
+ ASSERT(insertLeaf->entries().size() < C::LeafSize);
+ insertLeaf->entries().insert(extEntry, conf);
+
+ return interior;
+ }
+}
+
+#endif
diff --git a/src/mathic/BoolParameter.cpp b/src/mathic/BoolParameter.cpp
new file mode 100755
index 0000000..9e64ad5
--- /dev/null
+++ b/src/mathic/BoolParameter.cpp
@@ -0,0 +1,31 @@
+#include "BoolParameter.h"
+
+#include "error.h"
+
+namespace mathic {
+ BoolParameter::BoolParameter(const std::string& name,
+ const std::string& description,
+ bool defaultValue):
+ CliParameter(name, description),
+ _value(defaultValue) {
+ }
+
+ std::string BoolParameter::argumentType() const {
+ return "[BOOL]";
+ }
+
+ std::string BoolParameter::valueAsString() const {
+ return _value ? "on" : "off";
+ }
+
+ void BoolParameter::processArgument(const std::string& argument) {
+ if (argument.empty() || argument == "on")
+ _value = true;
+ else if (argument == "off")
+ _value = false;
+ else {
+ reportError("Option -" + name() + " was given the argument \"" +
+ argument + "\". The only valid arguments are \"on\" and \"off\".");
+ }
+ }
+}
diff --git a/src/mathic/BoolParameter.h b/src/mathic/BoolParameter.h
new file mode 100755
index 0000000..c10aea8
--- /dev/null
+++ b/src/mathic/BoolParameter.h
@@ -0,0 +1,31 @@
+#ifndef MATHIC_BOOL_PARAMETER_GUARD
+#define MATHIC_BOOL_PARAMETER_GUARD
+
+#include "stdinc.h"
+#include "CliParameter.h"
+#include <utility>
+#include <string>
+
+namespace mathic {
+ class BoolParameter : public CliParameter {
+ public:
+ BoolParameter(const std::string& name,
+ const std::string& description,
+ bool defaultValue);
+
+ bool value() const {return _value;}
+ void setValue(bool value) {_value = value;}
+
+ operator bool() const {return value();}
+ void operator=(bool value) {setValue(value);}
+
+ virtual std::string argumentType() const;
+ virtual std::string valueAsString() const;
+ virtual void processArgument(const std::string& argument);
+
+ private:
+ bool _value;
+ };
+}
+
+#endif
diff --git a/src/mathic/CliParameter.cpp b/src/mathic/CliParameter.cpp
new file mode 100755
index 0000000..2c15f5d
--- /dev/null
+++ b/src/mathic/CliParameter.cpp
@@ -0,0 +1,19 @@
+#include "CliParameter.h"
+#include "error.h"
+
+namespace mathic {
+ CliParameter::CliParameter(
+ const std::string& name,
+ const std::string& description
+ ):
+ _name(name),
+ _description(description) {
+ }
+
+ CliParameter::~CliParameter() {
+ }
+
+ void CliParameter::appendToDescription(const std::string& str) {
+ _description += str;
+ }
+}
diff --git a/src/mathic/CliParameter.h b/src/mathic/CliParameter.h
new file mode 100755
index 0000000..db89835
--- /dev/null
+++ b/src/mathic/CliParameter.h
@@ -0,0 +1,29 @@
+#ifndef MATHIC_PARAMETER_GUARD
+#define MATHIC_PARAMETER_GUARD
+
+#include "stdinc.h"
+#include <string>
+
+namespace mathic {
+ class CliParameter {
+ public:
+ virtual ~CliParameter();
+
+ const std::string& name() const {return _name;}
+ const std::string& description() const {return _description;}
+ void appendToDescription(const std::string& str);
+
+ virtual std::string argumentType() const = 0;
+ virtual std::string valueAsString() const = 0;
+ virtual void processArgument(const std::string& argument) = 0;
+
+ protected:
+ CliParameter(const std::string& name, const std::string& description);
+
+ private:
+ std::string _name;
+ std::string _description;
+ };
+}
+
+#endif
diff --git a/src/mathic/CliParser.cpp b/src/mathic/CliParser.cpp
new file mode 100644
index 0000000..6e6af75
--- /dev/null
+++ b/src/mathic/CliParser.cpp
@@ -0,0 +1,101 @@
+#include "CliParser.h"
+
+#include "error.h"
+#include "CliParameter.h"
+
+namespace mathic {
+ namespace {
+ // We are using a NameFactory just for its prefix-finding functionality, so
+ // we set the thing being created to be just void pointers that are null.
+ typedef void* Dummy;
+ typedef NameFactory<Dummy> ParamNames;
+ ParamNames makeParamNames(std::vector<CliParameter*> params) {
+ struct HoldsFunction { // work around for no local functions in old C++
+ static std::auto_ptr<Dummy> dummyCreate() {
+ return std::auto_ptr<Dummy>(0);
+ }
+ };
+
+ ParamNames names("option");
+ for (size_t i = 0; i < params.size(); ++i)
+ names.registerProduct(params[i]->name(), HoldsFunction::dummyCreate);
+ return names;
+ }
+ }
+
+ void CliParser::pushBackRegisteredActionNames(
+ std::vector<std::string>& names
+ ) const {
+ _actions.namesWithPrefix("", names);
+ }
+
+
+ CliParser::CliParser(): _actions("action") {}
+
+ std::auto_ptr<Action> CliParser::createActionWithPrefix(
+ const std::string& prefix
+ ) {
+ return createWithPrefix(_actions, prefix);
+ }
+
+ std::auto_ptr<Action> CliParser::parse(int argc, char** argv) {
+ std::vector<std::string> commandLine(argv, argv + argc);
+ return parse(commandLine);
+ }
+
+ std::auto_ptr<Action> CliParser::parse
+ (const std::vector<std::string>& commandLine) {
+ if (commandLine.empty())
+ throwError<UnknownNameException>("No action specified.");
+ std::auto_ptr<Action> action = createActionWithPrefix(commandLine[0]);
+
+ std::vector<CliParameter*> params;
+ action->pushBackParameters(params);
+ ParamNames paramNames = makeParamNames(params);
+
+ std::vector<std::string> options;
+ std::vector<std::string> directOptions;
+ bool sawDash = false;
+ for (size_t i = 1; i < commandLine.size(); ++i) {
+ if (commandLine[i].empty())
+ continue;
+ if (commandLine[i][0] == '-')
+ sawDash = true;
+ if (sawDash)
+ options.push_back(commandLine[i]);
+ else
+ directOptions.push_back(commandLine[i]);
+ }
+
+ action->directOptions(directOptions, *this);
+
+ size_t i = 1;
+ for (size_t i = 0; i < options.size(); ++i) {
+ std::string const& token = options[i];
+ if (token[0] != '-')
+ reportError("Expected an option when reading \"" +
+ token + "\", but options start with a dash (-).\n");
+ std::string noDash(token.begin() + 1, token.end());
+ std::string name = uniqueNameWithPrefix(paramNames, noDash);
+
+ std::string optionArgument;
+ if (i + 1 < options.size() && options[i + 1][0] != '-') {
+ optionArgument = options[i + 1];
+ ++i;
+ }
+
+ for (std::vector<CliParameter*>::iterator it = params.begin();; ++it) {
+ if (it == params.end()) {
+ // shouldn't get here as name was recognized above
+ reportInternalError("Processing non-existent option \""
+ + name + "\".");
+ }
+ if ((*it)->name() == name) {
+ (*it)->processArgument(optionArgument);
+ break;
+ }
+ }
+ }
+ return action;
+ }
+}
diff --git a/src/mathic/CliParser.h b/src/mathic/CliParser.h
new file mode 100644
index 0000000..22fcb42
--- /dev/null
+++ b/src/mathic/CliParser.h
@@ -0,0 +1,50 @@
+#ifndef MATHIC_CLI_PARSER_GUARD
+#define MATHIC_CLI_PARSER_GUARD
+
+#include "NameFactory.h"
+#include "Action.h"
+
+namespace mathic {
+ class CliParser {
+ public:
+ CliParser();
+
+ template<class ConcreteAction>
+ void registerAction(const std::string& name);
+
+ // picks the name up from ConcreteAction::staticName().
+ template<class ConcreteAction>
+ void registerAction();
+
+ void registerHelpAction
+ (const std::string& preMessage, const std::string& postMessage);
+
+ void pushBackRegisteredActionNames(
+ std::vector<std::string>& names
+ ) const;
+
+ const std::string& helpPreMessage() const {return _helpPreMessage;}
+ const std::string& helpPostMessage() const {return _helpPostMessage;}
+
+ std::auto_ptr<Action> parse(int argc, char** argv);
+ std::auto_ptr<Action> parse(const std::vector<std::string>& commandLine);
+ std::auto_ptr<Action> createActionWithPrefix(const std::string& prefix);
+
+ private:
+ NameFactory<Action> _actions;
+ std::string _helpPreMessage;
+ std::string _helpPostMessage;
+ };
+
+ template<class ConcreteAction>
+ void CliParser::registerAction(const std::string& name) {
+ nameFactoryRegister<ConcreteAction>(_actions, name);
+ };
+
+ template<class ConcreteAction>
+ void CliParser::registerAction() {
+ nameFactoryRegister<ConcreteAction>(_actions);
+ };
+}
+
+#endif
diff --git a/src/mathic/ColumnPrinter.cpp b/src/mathic/ColumnPrinter.cpp
new file mode 100755
index 0000000..92a760b
--- /dev/null
+++ b/src/mathic/ColumnPrinter.cpp
@@ -0,0 +1,185 @@
+#include "ColumnPrinter.h"
+
+namespace mathic {
+ namespace {
+ size_t getLineWidth(const std::string& str, size_t pos) {
+ size_t startPos = pos;
+ while (pos < str.size() && str[pos] != '\n')
+ ++pos;
+ return pos - startPos;
+ }
+
+ void printSpaces(std::ostream& out, size_t howMany) {
+ while (howMany > 0) {
+ out << ' ';
+ --howMany;
+ }
+ }
+ }
+
+ ColumnPrinter::ColumnPrinter(size_t columnCount):
+ _cols() {
+ while (columnCount > 0) {
+ addColumn();
+ --columnCount;
+ }
+ }
+
+ ColumnPrinter::~ColumnPrinter() {
+ for (std::vector<Col*>::iterator it = _cols.begin();
+ it != _cols.end(); ++it)
+ delete *it;
+ }
+
+ void ColumnPrinter::setPrefix(const std::string& prefix) {
+ _prefix = prefix;
+ }
+
+ void ColumnPrinter::addColumn(bool flushLeft,
+ const std::string& prefix,
+ const std::string& suffix) {
+ std::auto_ptr<Col> col(new Col());
+ col->prefix = prefix;
+ col->suffix = suffix;
+ col->flushLeft = flushLeft;
+
+ _cols.push_back(0);
+ _cols.back() = col.release(); // push_back didn't throw, so safe to release
+ }
+
+ size_t ColumnPrinter::getColumnCount() const {
+ return _cols.size();
+ }
+
+ std::ostream& ColumnPrinter::operator[](size_t col) {
+ MATHIC_ASSERT(col < getColumnCount());
+ return _cols[col]->text;
+ }
+
+ void ColumnPrinter::print(std::ostream& out) const {
+ // Calculate the width of each column.
+ std::vector<size_t> widths(getColumnCount());
+ for (size_t col = 0; col < getColumnCount(); ++col) {
+ const std::string& text = _cols[col]->text.str();
+ size_t maxWidth = 0;
+
+ size_t pos = 0;
+ while (pos < text.size()) {
+ size_t width = getLineWidth(text, pos);
+ if (width > maxWidth)
+ maxWidth = width;
+
+ // We can't just increment pos unconditionally by width + 1, as
+ // that could result in an overflow.
+ pos += width;
+ if (text[pos] == '\n')
+ ++pos;
+ }
+ widths[col] = maxWidth;
+ }
+
+ // Print each row
+ std::vector<size_t> poses(getColumnCount());
+ while (true) {
+ bool done = true;
+ for (size_t col = 0; col < getColumnCount(); ++col) {
+ if (poses[col] < _cols[col]->text.str().size()) {
+ done = false;
+ break;
+ }
+ }
+ if (done)
+ break;
+
+ out << _prefix;
+ for (size_t col = 0; col < getColumnCount(); ++col) {
+ out << _cols[col]->prefix;
+
+ const std::string& text = _cols[col]->text.str();
+ size_t& pos = poses[col];
+ size_t width = getLineWidth(text, pos);
+
+ if (!_cols[col]->flushLeft)
+ printSpaces(out, widths[col] - width);
+
+ while (pos < text.size()) {
+ if (text[pos] == '\n') {
+ ++pos;
+ break;
+ }
+ out << text[pos];
+ ++pos;
+ }
+
+ if (_cols[col]->flushLeft)
+ printSpaces(out, widths[col] - width);
+
+ out << _cols[col]->suffix;
+ }
+ out << '\n';
+ }
+ }
+
+ std::string ColumnPrinter::commafy(unsigned long long l) {
+ std::stringstream out;
+ out << l;
+ std::string str;
+ for (size_t i = 0; i < out.str().size(); ++i) {
+ str += out.str()[i];
+ if (i != out.str().size() - 1 && ((out.str().size() - i) % 3) == 1)
+ str += ',';
+ }
+ return str;
+ }
+
+ std::string ColumnPrinter::percent(
+ unsigned long long numerator,
+ unsigned long long denominator) {
+ return percent(static_cast<double>(numerator) / denominator);
+ }
+
+ std::string ColumnPrinter::percent(double ratio) {
+ return oneDecimal(ratio * 100) + '%';
+ }
+
+ std::string ColumnPrinter::ratio(
+ unsigned long long numerator,
+ unsigned long long denominator) {
+ return oneDecimal(static_cast<double>(numerator) / denominator);
+ }
+
+ std::string ColumnPrinter::oneDecimal(double d) {
+ std::ostringstream out;
+ unsigned long long l = static_cast<unsigned long long>(d * 10 + 0.5);
+ out << l / 10 << '.' << l % 10;
+ return out.str();
+ }
+
+ std::string ColumnPrinter::bytesInUnit(unsigned long long bytes) {
+ std::ostringstream out;
+ if (bytes < 1024) {
+ out << bytes << 'b';
+ } else {
+ const char* units[] = {"kb", "mb", "gb", "tb"};
+ const size_t unitCount = sizeof(units) / sizeof(*units);
+ double amount = static_cast<double>(bytes) / 1024.0;
+ size_t i = 0;
+ for (i = 0; i < unitCount && amount >= 1024; ++i)
+ amount /= 1024.0;
+ out << oneDecimal(amount) << units[i];
+ }
+ return out.str();
+ }
+
+
+ std::ostream& operator<<(std::ostream& out, const ColumnPrinter& printer) {
+ printer.print(out);
+ return out;
+ }
+
+ void print(FILE* out, const ColumnPrinter& pr) {
+ std::ostringstream str;
+ str << pr;
+ fputs(str.str().c_str(), out);
+ }
+}
diff --git a/src/mathic/ColumnPrinter.h b/src/mathic/ColumnPrinter.h
new file mode 100755
index 0000000..96ede3a
--- /dev/null
+++ b/src/mathic/ColumnPrinter.h
@@ -0,0 +1,64 @@
+#ifndef MATHIC_COLUMN_PRINTER_GUARD
+#define MATHIC_COLUMN_PRINTER_GUARD
+
+#include "stdinc.h"
+#include <sstream>
+#include <vector>
+#include <cstdio>
+#include <memory>
+#include <string>
+
+namespace mathic {
+ class ColumnPrinter {
+ public:
+ ColumnPrinter(size_t columnCount = 0);
+ ~ColumnPrinter();
+
+ void setPrefix(const std::string& prefix);
+ void addColumn(bool flushLeft = true,
+ const std::string& prefix = " ",
+ const std::string& suffix = "");
+ size_t getColumnCount() const;
+
+ std::ostream& operator[](size_t col);
+
+ void print(std::ostream& out) const;
+
+ /** returns 123456789 as "123,456,789". */
+ static std::string commafy(unsigned long long l);
+
+ /** returns (3,4) as "75.0%". */
+ static std::string percent(
+ unsigned long long numerator,
+ unsigned long long denominator);
+
+ /** returns 0.7565 as "75.7%". */
+ static std::string percent(double ratio);
+
+ /** Returns (7,4) as "1.8" */
+ static std::string ratio(
+ unsigned long long numerator,
+ unsigned long long denominator);
+
+ /** Returns d as a string printed to 1 decimal place, rounding up at 0.5 */
+ static std::string oneDecimal(double d);
+
+ /** Prints as X bytes, X kilobytes, X megabytes etc. */
+ static std::string bytesInUnit(unsigned long long bytes);
+
+ private:
+ struct Col {
+ std::string prefix;
+ std::stringstream text;
+ std::string suffix;
+ bool flushLeft;
+ };
+ std::vector<Col*> _cols;
+ std::string _prefix;
+ };
+
+ std::ostream& operator<<(std::ostream& out, const ColumnPrinter& printer);
+ void print(FILE* out, const ColumnPrinter& pr);
+}
+
+#endif
diff --git a/src/mathic/ComTree.h b/src/mathic/ComTree.h
new file mode 100644
index 0000000..dcc5d60
--- /dev/null
+++ b/src/mathic/ComTree.h
@@ -0,0 +1,273 @@
+#ifndef MATHIC_COM_TREE_GUARD
+#define MATHIC_COM_TREE_GUARD
+
+#include "stdinc.h"
+#include <ostream>
+
+namespace mathic {
+ /** This class packs a complete binary tree in a vector.
+
+ The idea is to have the root at index 1, and then the left child of node n
+ will be at index 2n and the right child will be at index 2n + 1. The
+ corresponding formulas when indexes start at 0 take more computation, so
+ we need a 1-based array so we can't use std::vector.
+
+ Also, when sizeof(Entry) is a power of 2 it is faster to keep track of
+ i * sizeof(Entry) than directly keeping track of an index i. This doesn't
+ work well when sizeof(Entry) is not a power of two. So we need both
+ possibilities. That is why this class never exposes indexes. Instead
+ you interact with Node objects that serve the role of an index, but the
+ precise value it stores is encapsulated. This way you can't do something
+ like _array[i * sizeof(Entry)] by accident. Client code also does not
+ need to (indeed, can't) be aware of how indexes are calculated, stored and
+ looked up.
+
+ If FastIndex is false, then Nodes contain an index i. If FastIndex is
+ true, then Nodes contain the byte offset i * sizeof(Entry). FastIndex must
+ be false if sizeof(Entry) is not a power of two.
+ */
+ template<class Entry, bool FastIndex>
+ class ComTree {
+ public:
+ class Node;
+ ComTree(size_t initialCapacity = 0);
+ ComTree(const ComTree& tree, size_t minCapacity = 0);
+ ~ComTree() {delete[](_array + 1);}
+
+ Entry& operator[](Node n);
+ const Entry& operator[](Node n) const;
+
+ bool empty() const {return _lastLeaf == Node(0);}
+ size_t size() const {return _lastLeaf.getNormalIndex();}
+ size_t capacity() const {return _capacityEnd.getNormalIndex();}
+ Node lastLeaf() const {return _lastLeaf;}
+
+ void pushBack(const Entry& value);
+ void pushBackWithCapacity(const Entry& value);
+ void popBack();
+
+ bool hasFreeCapacity(size_t extraCapacity) const;
+ void increaseCapacity();
+ void swap(ComTree& tree);
+
+ struct Node {
+ Node(): _index(fi ? S : 1) {} // the root node is the default
+
+ Node parent() const;
+ Node left() const;
+ Node right() const;
+ Node sibling() const;
+ Node leftSibling() const;
+ Node next() const;
+ Node next(size_t count) const;
+ Node prev() const;
+ Node& operator++() {*this = next(); return *this;}
+
+ bool isRoot() const {return *this == Node();}
+ bool isLeft() const {return fi ? !(_index & S) : !(_index & 1);}
+ bool isRight() const {return fi ? _index & S : _index & 1;}
+
+ bool operator<(Node node) const {return _index < node._index;}
+ bool operator<=(Node node) const {return _index <= node._index;}
+ bool operator>(Node node) const {return _index > node._index;}
+ bool operator>=(Node node) const {return _index >= node._index;}
+ bool operator==(Node node) const {return _index == node._index;}
+ bool operator!=(Node node) const {return _index != node._index;}
+
+ //private:
+ friend class ComTree<Entry, FastIndex>;
+ static const bool fi = FastIndex;
+ static const size_t S = sizeof(Entry);
+ explicit Node(size_t i): _index(i) {}
+ size_t getNormalIndex() const {return fi ? _index / S : _index;}
+ size_t _index;
+ };
+
+ void print(std::ostream& out) const;
+
+ void clear();
+
+ size_t getMemoryUse() const;
+
+#ifdef MATHIC_DEBUG
+ bool isValid() const;
+#endif
+
+ private:
+ ComTree& operator=(const ComTree& tree) const; // not available
+
+ Entry* _array;
+ Node _lastLeaf;
+ Node _capacityEnd;
+ };
+
+ template<class E, bool FI>
+ void ComTree<E, FI>::clear() {
+ _lastLeaf = Node(0);
+ }
+
+ template<class E, bool FI>
+ size_t ComTree<E, FI>::getMemoryUse() const {
+ return capacity() * sizeof(E);
+ }
+
+ template<class E, bool FI>
+ std::ostream& operator<<(std::ostream& out, const ComTree<E, FI>& tree) {
+ tree.print(out);
+ return out;
+ }
+
+ template<class E, bool FI>
+ ComTree<E, FI>::ComTree(size_t initialCapacity):
+ _array(static_cast<E*>(0) - 1),
+ _lastLeaf(0),
+ _capacityEnd(Node(0).next(initialCapacity)) {
+ if (initialCapacity > 0)
+ _array = new E[initialCapacity] - 1;
+ MATHIC_ASSERT(isValid());
+ }
+
+ template<class E, bool FI>
+ ComTree<E, FI>::ComTree(const ComTree& tree, size_t minCapacity):
+ _array(static_cast<E*>(0) - 1),
+ _lastLeaf(tree._lastLeaf) {
+ if (tree.size() > minCapacity)
+ minCapacity = tree.size();
+ _capacityEnd = Node(0).next(minCapacity);
+ if (minCapacity == 0)
+ return;
+ _array = new E[minCapacity] - 1;
+ for (Node i; i <= tree.lastLeaf(); ++i)
+ (*this)[i] = tree[i];
+ }
+
+ template<class E, bool FI>
+ E& ComTree<E, FI>::operator[](Node n) {
+ if (!FI)
+ return _array[n._index];
+ char* base = reinterpret_cast<char*>(_array);
+ E* element = reinterpret_cast<E*>(base + n._index);
+ MATHIC_ASSERT(element == &(_array[n._index / sizeof(E)]));
+ return *element;
+ }
+
+ template<class E, bool FI>
+ const E& ComTree<E, FI>::operator[](Node n) const {
+ return const_cast<ComTree<E, FI>*>(this)->operator[](n);
+ }
+
+ template<class E, bool FI>
+ void ComTree<E, FI>::pushBack(const E& value) {
+ if (_lastLeaf == _capacityEnd)
+ increaseCapacity();
+ _lastLeaf = _lastLeaf.next();
+ (*this)[lastLeaf()] = value;
+ }
+
+ template<class E, bool FI>
+ void ComTree<E, FI>::pushBackWithCapacity(const E& value) {
+ MATHIC_ASSERT(_lastLeaf != _capacityEnd);
+ _lastLeaf = _lastLeaf.next();
+ (*this)[lastLeaf()] = value;
+ }
+
+ template<class E, bool FI>
+ void ComTree<E, FI>::popBack() {
+ MATHIC_ASSERT(_lastLeaf >= Node());
+ _lastLeaf = _lastLeaf.prev();
+ }
+
+ template<class E, bool FI>
+ void ComTree<E, FI>::swap(ComTree& tree) {
+ std::swap(_array, tree._array);
+ std::swap(_lastLeaf, tree._lastLeaf);
+ std::swap(_capacityEnd, tree._capacityEnd);
+ }
+
+ template<class E, bool FI>
+ typename ComTree<E, FI>::Node ComTree<E, FI>::Node::parent() const {
+ return fi ? Node((_index / (2 * S)) * S) : Node(_index / 2);
+ }
+
+ template<class E, bool FI>
+ typename ComTree<E, FI>::Node ComTree<E, FI>::Node::left() const {
+ return Node(2 * _index);
+ }
+
+ template<class E, bool FI>
+ typename ComTree<E, FI>::Node ComTree<E, FI>::Node::right() const {
+ return fi ? Node(2 * _index + S) : Node(2 * _index + 1);
+ }
+
+ template<class E, bool FI>
+ typename ComTree<E, FI>::Node ComTree<E, FI>::Node::sibling() const {
+ return fi ? Node(_index ^ S) : Node(_index ^ 1);
+ }
+
+ template<class E, bool FI>
+ typename ComTree<E, FI>::Node ComTree<E, FI>::Node::leftSibling() const {
+ return fi ? Node(_index & ~S) : Node(_index & ~1);
+ }
+
+ template<class E, bool FI>
+ typename ComTree<E, FI>::Node ComTree<E, FI>::Node::next() const {
+ return fi ? Node(_index + S) : Node(_index + 1);
+ }
+
+ template<class E, bool FI>
+ typename ComTree<E, FI>::Node ComTree<E, FI>::Node::next(size_t count) const {
+ return fi ? Node(_index + S * count) : Node(_index + count);
+ }
+
+ template<class E, bool FI>
+ typename ComTree<E, FI>::Node ComTree<E, FI>::Node::prev() const {
+ return fi ? Node(_index - S) : Node(_index - 1);
+ }
+
+ template<class E, bool FI>
+ void ComTree<E, FI>::print(std::ostream& out) const {
+ Node last = lastLeaf();
+ for (Node i; i <= last; i = i.next()) {
+ if ((i._index & (i._index - 1)) == 0) // if i._index is a power of 2
+ out << "\n " << i._index << ':';
+ out << ' ' << (*this)[i];
+ }
+ out << "}\n";
+ }
+
+#ifdef MATHIC_DEBUG
+ template<class E, bool FI>
+ bool ComTree<E, FI>::isValid() const {
+ // sizeof(Entry) must be a power of two if FastIndex is true.
+ MATHIC_ASSERT(!FI || (sizeof(E) & (sizeof(E) - 1)) == 0);
+ if (capacity() == 0) {
+ MATHIC_ASSERT(_array == static_cast<E*>(0) - 1);
+ MATHIC_ASSERT(_capacityEnd == Node(0));
+ MATHIC_ASSERT(_lastLeaf == Node(0));
+ } else {
+ MATHIC_ASSERT(_array != static_cast<E*>(0) - 1);
+ MATHIC_ASSERT(_capacityEnd > Node(0));
+ MATHIC_ASSERT(_lastLeaf <= _capacityEnd);
+ }
+ return true;
+ }
+#endif
+
+ template<class E, bool FI>
+ bool ComTree<E, FI>::hasFreeCapacity(size_t extraCapacity) const {
+ return Node(_capacityEnd._index - _lastLeaf._index) >=
+ Node(0).next(extraCapacity);
+ }
+
+ template<class E, bool FI>
+ void ComTree<E, FI>::increaseCapacity() {
+ ComTree<E, FI> newTree(capacity() == 0 ? 16 : capacity() * 2);
+ for (Node i; i <= lastLeaf(); i = i.next())
+ newTree.pushBack((*this)[i]);
+ std::swap(_array, newTree._array);
+ std::swap(_capacityEnd, newTree._capacityEnd);
+ MATHIC_ASSERT(isValid());
+ }
+}
+
+#endif
diff --git a/src/mathic/Comparer.h b/src/mathic/Comparer.h
new file mode 100644
index 0000000..6f60bac
--- /dev/null
+++ b/src/mathic/Comparer.h
@@ -0,0 +1,18 @@
+#ifndef MATHIC_COMPARER_GUARD
+#define MATHIC_COMPARER_GUARD
+
+namespace mathic {
+ template<class C>
+ class Comparer {
+ public:
+ Comparer(const C& conf): _conf(conf) {}
+ template<class A, class B>
+ bool operator()(const A& a, const B& b) const {
+ return _conf.isLessThan(a.get(), b.get());
+ }
+ private:
+ const C& _conf;
+ };
+}
+
+#endif
diff --git a/src/mathic/DivFinder.h b/src/mathic/DivFinder.h
new file mode 100755
index 0000000..7fbb933
--- /dev/null
+++ b/src/mathic/DivFinder.h
@@ -0,0 +1,74 @@
+#ifndef MATHIC_DIV_FINDER_GUARD
+#define MATHIC_DIV_FINDER_GUARD
+
+/** An object that supports queries for divisors of a monomial.
+
+ This is an object for documentation purposes. Use the concrete
+ implementations of this interface to get an actual DivFinder-like
+ object.
+
+ DivFinder stores configurable Entry objects that represent a monomial
+ together with any required additional information.
+
+ The class is parameterized on a Configuration. The Configuration class
+ must have the following members.
+
+ * A type Monomial
+ Represents a monomial.
+
+ * A type Entry
+ These are the things added to the finder. Entry represents a monomial
+ along with any additional required information that client code needs
+ to associate with monomials in the finder.
+
+ * A type Exponent
+ These are exponents of the monomials. Exponent must have a copy constructor,
+ an operator= and an operator< for comparision with other exponents.
+
+ * A function Exponent getExponent(Monomial m, size_t var) const
+ Returns the exponent of the variable var in m. m can be a const reference.
+
+ * A function bool divides(Entry a, Monomial b) const
+ * A function bool divides(Monomial a, Entry b) const
+ * A function bool divides(Entry a, Entry b) const
+ Returns whether a divides b. a and b can be const references. If Entry
+ and Monomial are the same type then only one function is needed.
+
+ * A function size_t getVarCount() const
+ Returns the number of variables. Variables are indexed from 0 to
+ getVarCount() - 1. Must be a positive number.
+
+ * static const bool UseDivMask
+ Set to true to use div masks to speed up queries. This must be a
+ static const data member.
+
+ * size_t getUseAutomaticRebuild() const
+ * double getRebuildRatio() const
+ * size_t getRebuildMin() const
+ If getUseAutomaticRebuild() returns true, the tree will call rebuild
+ after a total of max(size() * getRebuildRatio(), getRebuildMin())
+ entry insertions and removals have occurred. A rebuild ratio of 0.5
+ and a minimum of 500 has worked well for random vectors.
+
+ * A method bool isLessThan(Entry a, Monomial b) const
+ * A method bool isLessThan(Monomial a, Entry b) const
+ * A method bool isLessThan(Entry a, Entry b) const
+ isLessThan must define a total order < on entries/monomials. a and b can
+ be const references. If Entry and Monomial are the same type then only
+ one function is needed.
+
+ It is possible to obtain non-const Entries from a DivFinder. It is allowed
+ to change these, but the monomial they represent must not change. When the
+ DivFinder calls some method X on the Configuration, the Configuration must
+ not in return cause a method to be called on the DivFinder until the method
+ X has returned. This is because the DivFinder may not be in a valid state
+ at the time it is calling X.
+
+ @todo: put these docs somewhere else.
+*/
+namespace {
+ template<class Configuration>
+ class DivFinder; // no implementation
+}
+
+#endif
diff --git a/src/mathic/DivList.h b/src/mathic/DivList.h
new file mode 100755
index 0000000..1f5928a
--- /dev/null
+++ b/src/mathic/DivList.h
@@ -0,0 +1,616 @@
+#ifndef MATHIC_DIV_ARRAY_GUARD
+#define MATHIC_DIV_ARRAY_GUARD
+
+#include "stdinc.h"
+#include "DivMask.h"
+#include "Comparer.h"
+#include <memtailor.h>
+#include <vector>
+#include <string>
+#include <list>
+#include <algorithm>
+#include <sstream>
+
+namespace mathic {
+ /** An object that supports queries for divisors of a monomial using
+ an array of monomials. See DivFinder for more documentation.
+
+ Extra fields for Configuration:
+
+ * static const bool UseLinkedList
+ Use a linked list if true, otherwise use an array.
+
+ * static const bool UseDivMask
+ Use div masks if true.
+
+ * bool getSortOnInsert() const
+ Keep the monomials sorted to speed up queries.
+ */
+ template<class Configuration>
+ class DivList;
+
+ namespace DivListHelper {
+ // Implementation details for DivList.
+
+ template<bool B, class E>
+ struct ListImpl;
+
+ template<class Entry>
+ struct ListImpl<false, Entry> {
+ typedef std::vector<Entry> Impl;
+ };
+ template<class Entry>
+ struct ListImpl<true, Entry> {
+ typedef std::list<Entry> Impl;
+ };
+ }
+
+ template<class C>
+ class DivList {
+ public:
+ typedef C Configuration;
+ typedef typename C::Entry Entry;
+ typedef typename C::Monomial Monomial;
+ typedef typename C::Exponent Exponent;
+
+ static const bool UseLinkedList = C::UseLinkedList;
+ static const bool UseDivMask = C::UseDivMask;
+
+ private:
+ typedef typename DivMask::Extender<Entry, C::UseDivMask> ExtEntry;
+ typedef typename DivMask::Extender<const Monomial&,C::UseDivMask> ExtMonoRef;
+ typedef typename DivMask::Calculator<C> DivMaskCalculator;
+
+ typedef typename DivListHelper::ListImpl<C::UseLinkedList, ExtEntry>::Impl
+ List;
+ typedef typename List::iterator ListIter;
+ typedef typename List::const_iterator CListIter;
+
+ public:
+ class iterator;
+ class const_iterator;
+
+ DivList(const C& configuration);
+
+ template<class Iter>
+ void insert(Iter begin, Iter end);
+ void insert(const Entry& entry);
+
+ bool removeMultiples(const Monomial& monomial);
+ template<class MultipleOutput>
+ bool removeMultiples
+ (const Monomial& monomial, MultipleOutput& out);
+
+ bool removeElement(const Monomial& monomial);
+
+ iterator findDivisorIterator(const Monomial& monomial);
+
+ Entry* findDivisor(const Monomial& monomial);
+ const Entry* findDivisor(const Monomial& monomial) const;
+
+ template<class DO>
+ void findAllDivisors(const Monomial& monomial, DO& out);
+ template<class DO>
+ void findAllDivisors(const Monomial& monomial, DO& out) const;
+
+ template<class DO>
+ void findAllMultiples(const Monomial& monomial, DO& out);
+
+ template<class Output>
+ void findAllMultiples(const Monomial& monomial, Output& output) const {
+ ConstEntryOutput<Output> constOutput(output);
+ const_cast<DivList<C>&>(*this).findAllMultiples(monomial, constOutput);
+ }
+
+ template<class EntryOutput>
+ void forAll(EntryOutput& output);
+ template<class EntryOutput>
+ void forAll(EntryOutput& output) const;
+
+ iterator begin() {return iterator(_list.begin());}
+ const_iterator begin() const {return const_iterator(_list.begin());}
+ iterator end() {return iterator(_list.end());}
+ const_iterator end() const {return const_iterator(_list.end());}
+
+ bool empty() const {return _list.empty();}
+ size_t size() const {return _list.size();}
+
+ std::string getName() const;
+
+ C& getConfiguration() {return _conf;}
+ const C& getConfiguration() const {return _conf;}
+
+ void moveToFront(iterator pos);
+
+ void rebuild();
+
+ /** Returns the number of bytes allocated by this object. Does not
+ include sizeof(*this), does not include any additional memory
+ that the configuration may have allocated and does not include
+ any memory that an Entry may point to. Does include
+ sizeof(Entry) as well as unused memory that is being kept to
+ avoid frequent allocations. */
+ size_t getMemoryUse() const;
+
+ private:
+ DivList(const DivList<C>&); // unavailable
+ void operator=(const DivList<C>&); // unavailable
+
+ void resetNumberOfChangesTillRebuild();
+ void reportChanges(size_t changesMadeCount);
+
+ template<class DO>
+ class ConstEntryOutput {
+ public:
+ ConstEntryOutput(DO& out): _out(out) {}
+ bool proceed(const Entry& entry) {return _out.proceed(entry);}
+ private:
+ DO& _out;
+ };
+ class DummyMultipleOutput {
+ public:
+ void push_back(Entry& e) {}
+ };
+
+ List _list;
+ C _conf;
+ DivMaskCalculator _divMaskCalculator;
+ size_t _changesTillRebuild; /// Update using reportChanges().
+ };
+
+ template<class C>
+ class DivList<C>::const_iterator :
+ public std::iterator<std::bidirectional_iterator_tag, const Entry> {
+ public:
+ friend class DivList<C>;
+ explicit const_iterator(CListIter it): _it(it) {}
+ bool operator==(const_iterator it) {return _it == it._it;}
+ bool operator!=(const_iterator it) {return _it != it._it;}
+ bool operator==(iterator it) {return *this == const_iterator(it);}
+ bool operator!=(iterator it) {return *this != const_iterator(it);}
+
+ const Entry& operator*() const {return _it->get();}
+ const Entry* operator->() const {return &_it->get();}
+
+ const_iterator& operator++() {++_it; return *this;}
+ const_iterator operator++(int) {
+ const_iterator tmp = *this;
+ operator++();
+ return tmp;
+ }
+ const_iterator& operator--() {--_it; return *this;}
+ const_iterator operator--(int) {
+ const_iterator tmp = *this;
+ operator--();
+ return tmp;
+ }
+
+ protected:
+ ListIter getInternal() {return _it;}
+
+ private:
+ CListIter _it;
+ };
+
+ template<class C>
+ class DivList<C>::iterator :
+ public std::iterator<std::bidirectional_iterator_tag, Entry> {
+ public:
+ friend class DivList<C>;
+ explicit iterator(ListIter it): _it(it) {}
+ operator const_iterator() const {return const_iterator(_it);}
+
+ bool operator==(iterator it) {return _it == it._it;}
+ bool operator!=(iterator it) {return _it != it._it;}
+ bool operator==(const_iterator it) {return it == const_iterator(*this);}
+ bool operator!=(const_iterator it) {return it != const_iterator(*this);}
+
+ iterator& operator++() {++_it; return *this;}
+ iterator operator++(int) {iterator tmp = *this; operator++(); return tmp;}
+ iterator& operator--() {--_it; return *this;}
+ iterator operator--(int) {iterator tmp = *this; operator--(); return tmp;}
+
+ Entry& operator*() const {return _it->get();}
+ Entry* operator->() const {return &_it->get();}
+
+ protected:
+ ListIter getInternal() {return _it;}
+
+ private:
+ ListIter _it;
+ };
+
+ namespace DivListHelper {
+ template<class C, class E, class M, class MO>
+ size_t removeMultiples
+ (C& conf, std::vector<E>& list, const M& monomial, MO& out) {
+ typedef typename std::vector<E>::iterator iterator;
+ iterator it = list.begin();
+ iterator oldEnd = list.end();
+ for (; it != oldEnd; ++it) {
+ if (monomial.divides(*it, conf)) {
+ out.push_back(it->get());
+ break;
+ }
+ }
+ if (it == oldEnd)
+ return 0;
+ iterator newEnd = it;
+ for (++it; it != oldEnd; ++it) {
+ if (!monomial.divides(*it, conf)) {
+ *newEnd = *it;
+ ++newEnd;
+ } else
+ out.push_back(it->get());
+ }
+ const size_t origSize = list.size();
+ const size_t newSize = std::distance(list.begin(), newEnd);
+ MATHIC_ASSERT(newSize < list.size());
+ list.resize(newSize);
+ return origSize - newSize;
+ }
+
+ template<class C, class E, class M, class MO>
+ size_t removeMultiples(C& conf,
+ std::list<E>& list,
+ const M& monomial,
+ MO& out) {
+#ifdef MATHIC_DEBUG
+ const size_t origSize = list.size();
+#endif
+ typedef typename std::list<E>::iterator iterator;
+ iterator it = list.begin();
+ iterator oldEnd = list.end();
+ size_t removedCount = 0;
+ while (it != oldEnd) {
+ if (monomial.divides(*it, conf)) {
+ out.push_back(it->get());
+ ++removedCount;
+ it = list.erase(it);
+ } else
+ ++it;
+ }
+ MATHIC_ASSERT(list.size() + removedCount == origSize);
+ return removedCount;
+ }
+
+ template<class E, class It>
+ void moveToFront(std::vector<E>& list, It pos) {
+ E valueToMove = *pos;
+ It begin = list.begin();
+ while (pos != begin) {
+ It prev = pos;
+ --pos;
+ *prev = *pos;
+ }
+ list.front() = valueToMove;
+ }
+
+ template<class E, class It>
+ void moveToFront(std::list<E>& list, It pos) {
+ list.splice(list.begin(), list, pos);
+ }
+
+ template<class C, class E>
+ typename std::list<E>::iterator
+ insertSort(C& conf, std::list<E>& list, const E& entry) {
+ typedef typename std::list<E>::iterator iterator;
+ iterator end = list.end();
+ iterator it = list.begin();
+ for (; it != end; ++it)
+ if (conf.isLessThan(entry.get(), it->get()))
+ break;
+ return list.insert(it, entry);
+ }
+
+ template<class C, class E>
+ typename std::vector<E>::iterator
+ insertSort(C& conf, std::vector<E>& list, const E& entry) {
+ typedef typename std::vector<E>::iterator iterator;
+ iterator it = std::upper_bound(list.begin(), list.end(), entry,
+ Comparer<C>(conf));
+ return list.insert(it, entry);
+ }
+
+ template<class C, class E>
+ void sortAll(C& conf, std::list<E>& list) {
+ list.sort(Comparer<C>(conf));
+ }
+
+ template<class C, class E>
+ void sortAll(C& conf, std::vector<E>& list) {
+ std::sort(list.begin(), list.end(), Comparer<C>(conf));
+ }
+
+ template<class C, class E, class M>
+ typename std::vector<E>::iterator
+ findDivisorSorted(C& conf, std::vector<E>& list, const M& monomial) {
+ typedef typename std::vector<E>::iterator iterator;
+ iterator rangeEnd =
+ std::upper_bound(list.begin(), list.end(), monomial, Comparer<C>(conf));
+ iterator it = list.begin();
+ for (; it != rangeEnd; ++it)
+ if (it->divides(monomial, conf))
+ return it;
+ return list.end();
+ }
+
+ template<class C, class E, class M>
+ typename std::list<E>::iterator
+ findDivisorSorted(C& conf, std::list<E>& list, const M& monomial) {
+ typedef typename std::list<E>::iterator iterator;
+ iterator end = list.end();
+ iterator it = list.begin();
+ size_t count = 0;
+ for (; it != end; ++it) {
+ ++count;
+ if (count == 35) {
+ count = 0;
+ if (conf.isLessThan(monomial.get(), it->get()))
+ break;
+ }
+ if (it->divides(monomial, conf))
+ return it;
+ }
+ return end;
+ }
+
+ template<class C, class E, class M, class DO>
+ void findAllDivisorsSorted
+ (C& conf, std::vector<E>& list, const M& monomial, DO& out) {
+ typedef typename std::vector<E>::iterator iterator;
+ iterator rangeEnd =
+ std::upper_bound(list.begin(), list.end(), monomial, Comparer<C>(conf));
+ iterator it = list.begin();
+ for (; it != rangeEnd; ++it)
+ if (it->divides(monomial, conf))
+ if (!out.proceed(it->get()))
+ break;
+ }
+
+ template<class C, class E, class M, class O>
+ void findAllDivisorsSorted
+ (C& conf, std::list<E>& list, const M& monomial, O& out) {
+ typedef typename std::list<E>::iterator iterator;
+ iterator end = list.end();
+ iterator it = list.begin();
+ size_t count = 0;
+ for (; it != end; ++it) {
+ ++count;
+ if (count == 35) {
+ count = 0;
+ if (conf.isLessThan(monomial.get(), it->get()))
+ break;
+ }
+ if (it->divides(monomial, conf))
+ if (!out.proceed(it->get()))
+ break;
+ }
+ }
+ }
+
+ template<class C>
+ DivList<C>::DivList(const C& configuration):
+ _conf(configuration),
+ _divMaskCalculator(configuration) {
+ resetNumberOfChangesTillRebuild();
+ }
+
+ template<class C>
+ void DivList<C>::insert(const Entry& entry) {
+ ExtEntry extEntry(entry, _divMaskCalculator, _conf);
+
+ if (!_conf.getSortOnInsert())
+ _list.push_back(extEntry);
+ else
+ DivListHelper::insertSort(_conf, _list, extEntry);
+ reportChanges(1);
+ }
+
+ template<class C>
+ template<class Iter>
+ void DivList<C>::insert(Iter rangeBegin, Iter rangeEnd) {
+ if (!empty()) {
+ for (; rangeBegin != rangeEnd; ++rangeBegin)
+ insert(*rangeBegin);
+ return;
+ }
+ if (rangeBegin == rangeEnd)
+ return;
+
+ _divMaskCalculator.rebuild(rangeBegin, rangeEnd, _conf);
+ for (; rangeBegin != rangeEnd; ++rangeBegin)
+ _list.push_back(ExtEntry(*rangeBegin, _divMaskCalculator, _conf));
+ if (_conf.getSortOnInsert())
+ DivListHelper::sortAll(_conf, _list);
+ resetNumberOfChangesTillRebuild();
+ }
+
+ template<class C>
+ template<class MO>
+ bool DivList<C>::removeMultiples(const Monomial& monomial, MO& out) {
+ ExtMonoRef extMonomial(monomial, _divMaskCalculator, _conf);
+#ifdef MATHIC_DEBUG
+ const size_t origSize = size();
+#endif
+ const size_t removedCount =
+ DivListHelper::removeMultiples(_conf, _list, extMonomial, out);
+ MATHIC_ASSERT(size() + removedCount == origSize);
+ reportChanges(removedCount);
+ return removedCount > 0;
+ }
+
+ template<class C>
+ bool DivList<C>::removeMultiples(const Monomial& monomial) {
+ DummyMultipleOutput out;
+ return removeMultiples(monomial, out);
+ }
+
+ template<class C>
+ bool DivList<C>::removeElement(const Monomial& monomial) {
+ const size_t varCount = _conf.getVarCount();
+ for (ListIter it = _list.begin(); it != _list.end(); ++it) {
+ for (size_t var = 0; var < varCount; ++var) {
+ if (_conf.getExponent(monomial, var) !=
+ _conf.getExponent(it->get(), var)) {
+ goto skip;
+ }
+ }
+ _list.erase(it);
+ return true;
+ skip:;
+ }
+ return false;
+ }
+
+ template<class C>
+ typename DivList<C>::iterator
+ DivList<C>::findDivisorIterator(const Monomial& monomial) {
+ ExtMonoRef extMonomial(monomial, _divMaskCalculator, _conf);
+
+ if (!_conf.getSortOnInsert()) {
+ ListIter listEnd = _list.end();
+ for (ListIter it = _list.begin(); it != listEnd; ++it) {
+ if (it->divides(extMonomial, _conf))
+ return iterator(it);
+ }
+ return iterator(listEnd);
+ } else
+ return iterator(DivListHelper::findDivisorSorted(_conf, _list, extMonomial));
+ }
+
+ template<class C>
+ typename DivList<C>::Entry*
+ DivList<C>::findDivisor(const Monomial& monomial) {
+ ExtMonoRef extMonomial(monomial, _divMaskCalculator, _conf);
+
+ if (!_conf.getSortOnInsert()) {
+ const ListIter listEnd = _list.end();
+ for (ListIter it = _list.begin(); it != listEnd; ++it) {
+ if (it->divides(extMonomial, _conf))
+ return &it->get();
+ }
+ return 0;
+ } else {
+ ListIter it = DivListHelper::findDivisorSorted(_conf, _list, extMonomial);
+ return it == _list.end() ? 0 : &it->get();
+ }
+ }
+
+ template<class C>
+ const typename DivList<C>::Entry*
+ DivList<C>::findDivisor(const Monomial& monomial) const {
+ return const_cast<DivList<C>&>(*this).findDivisor(monomial);
+ }
+
+ template<class C>
+ template<class DO>
+ void DivList<C>::findAllDivisors(const Monomial& monomial, DO& out) {
+ ExtMonoRef extMonomial(monomial, _divMaskCalculator, _conf);
+ if (!_conf.getSortOnInsert()) {
+ const ListIter listEnd = _list.end();
+ for (ListIter it = _list.begin(); it != listEnd; ++it)
+ if (it->divides(extMonomial, _conf))
+ if (!out.proceed(it->get()))
+ break;
+ } else
+ DivListHelper::findAllDivisorsSorted(_conf, _list, extMonomial, out);
+ }
+
+ template<class C>
+ template<class DO>
+ void DivList<C>::findAllMultiples(const Monomial& monomial, DO& out) {
+ // todo: consider doing sorted version
+ ExtMonoRef extMonomial(monomial, _divMaskCalculator, _conf);
+ const ListIter listEnd = _list.end();
+ for (ListIter it = _list.begin(); it != listEnd; ++it)
+ if (extMonomial.divides(*it, _conf))
+ if (!out.proceed(it->get()))
+ break;
+ }
+
+ template<class C>
+ template<class DO>
+ void DivList<C>::findAllDivisors(const Monomial& monomial,
+ DO& output) const {
+ ConstEntryOutput<DO> constOutput(output);
+ const_cast<DivList<C>&>(*this).findAllDivisors(monomial, constOutput);
+ }
+
+ template<class C>
+ template<class EntryOutput>
+ void DivList<C>::forAll(EntryOutput& output) {
+ iterator stop = end();
+ for (iterator it = begin(); it != stop; ++it)
+ if (!output.proceed(*it))
+ return;
+ }
+
+ template<class C>
+ template<class EntryOutput>
+ void DivList<C>::forAll(EntryOutput& output) const {
+ ConstEntryOutput<EntryOutput> constOutput(output);
+ const_cast<DivList<C>&>(*this).forAll(constOutput);
+ }
+
+ template<class C>
+ std::string DivList<C>::getName() const {
+ std::ostringstream out;
+ out <<"DivList"
+ << (UseLinkedList ? " linked" : " array");
+ if (UseDivMask && _conf.getDoAutomaticRebuilds()) {
+ out << " autob:" << _conf.getRebuildRatio()
+ << '/' << _conf.getRebuildMin();
+ }
+ out << (_conf.getSortOnInsert() ? " sort" : "")
+ << (UseDivMask ? " dmask" : "");
+ return out.str();
+ }
+
+ template<class C>
+ void DivList<C>::moveToFront(iterator pos) {
+ DivListHelper::moveToFront(_list, pos.getInternal());
+ }
+
+ template<class C>
+ void DivList<C>::rebuild() {
+ const size_t totalSize = size();
+ typedef memt::ArenaVector<Entry, true> TmpContainer;
+ TmpContainer tmpCopy(memt::Arena::getArena(), totalSize);
+ std::copy(begin(), end(), std::back_inserter<TmpContainer>(tmpCopy));
+ _divMaskCalculator.rebuild(tmpCopy.begin(), tmpCopy.end(), _conf);
+ ListIter listEnd = _list.end();
+ for (ListIter it = _list.begin(); it != listEnd; ++it)
+ it->recalculateDivMask(_divMaskCalculator, _conf);
+ resetNumberOfChangesTillRebuild();
+ }
+
+ template<class C>
+ void DivList<C>::resetNumberOfChangesTillRebuild() {
+ if (!_conf.getDoAutomaticRebuilds())
+ return;
+ MATHIC_ASSERT(_conf.getRebuildRatio() > 0);
+ _changesTillRebuild = std::max
+ (static_cast<size_t>(size() * _conf.getRebuildRatio()),
+ _conf.getRebuildMin());
+ }
+
+ template<class C>
+ void DivList<C>::reportChanges(size_t changesMadeCount) {
+ // note how negative value/overflow of _changesTillRebuild cannot
+ // happen this way.
+ if (!_conf.getDoAutomaticRebuilds())
+ return;
+ if (_changesTillRebuild > changesMadeCount)
+ _changesTillRebuild -= changesMadeCount;
+ else
+ rebuild();
+ }
+
+ template<class C>
+ size_t DivList<C>::getMemoryUse() const {
+ return _list.capacity() * sizeof(_list.front());
+ }
+}
+
+#endif
diff --git a/src/mathic/DivMask.cpp b/src/mathic/DivMask.cpp
new file mode 100644
index 0000000..bc4b1fa
--- /dev/null
+++ b/src/mathic/DivMask.cpp
@@ -0,0 +1,14 @@
+#include "DivMask.h"
+
+#ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO
+namespace mathic {
+ namespace DivMaskStats {
+ unsigned long maskComputes = 0;
+ unsigned long maskChecks = 0;
+ unsigned long maskHits = 0;
+ unsigned long divChecks = 0;
+ unsigned long divDivides = 0;
+ unsigned long divHits = 0;
+ }
+}
+#endif
diff --git a/src/mathic/DivMask.h b/src/mathic/DivMask.h
new file mode 100644
index 0000000..96f4bb9
--- /dev/null
+++ b/src/mathic/DivMask.h
@@ -0,0 +1,463 @@
+#ifndef MATHIC_BIT_MASK_GUARD
+#define MATHIC_BIT_MASK_GUARD
+
+#include "stdinc.h"
+#include <vector>
+#include <utility>
+#include <algorithm>
+
+// Value x means do 2^x mask checks before printing stats
+//#define MATHIC_TRACK_DIV_MASK_HIT_RATIO 25
+//#define MATHIC_TRACK_DIV_MASK_HIT_RATIO 30
+#ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO
+#include <iostream>
+#include "ColumnPrinter.h"
+#endif
+
+namespace mathic {
+#ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO
+ namespace DivMaskStats {
+ extern unsigned long maskComputes; // div masks computed
+ extern unsigned long maskChecks; // how many times mask is checked
+ extern unsigned long maskHits; // times canDivide returns false
+ extern unsigned long divChecks; // times divisibility is checked with mask
+ extern unsigned long divDivides; // mask can't hit as there is divisibility
+ extern unsigned long divHits; // times mask rules out divisibility
+ }
+#endif
+
+ /** Class representing a div mask. This is a set of bits that can
+ be used to determine that one monomial cannot divide another
+ monomial. */
+ class DivMask {
+ public:
+ /** Calculates div masks. Don't change NullCalculator
+ from its default value. The actual code are in partial specializations
+ selecting the right version based on NullCalculator. */
+ template<class Configuration,
+ bool NullCalculator = Configuration::UseDivMask>
+ class Calculator;
+
+ DivMask(): _mask(0) {}
+ static DivMask getMaxMask() {return ~static_cast<MaskType>(0);}
+
+ template<class T, class Configuration>
+ DivMask(const T& t,
+ const Calculator<Configuration>& calc, const Configuration& conf):
+ _mask(calc.compute(t, conf)) {}
+
+ template<class T, class Configuration>
+ void recalculate(const T& t,
+ const Calculator<Configuration>& calc,
+ const Configuration& conf) {
+ _mask = calc.compute(t, conf);
+ }
+
+ bool canDivide(const DivMask& mask) const {
+ const bool canDiv = ((_mask & ~mask._mask) == 0);
+#ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO
+ ++DivMaskStats::maskChecks;
+ if (!canDiv)
+ ++DivMaskStats::maskHits;
+
+ // print stats every 2^MATHIC_TRACK_DIV_MASK_HIT_RATIO time
+ const unsigned long mod = (1 << MATHIC_TRACK_DIV_MASK_HIT_RATIO) - 1;
+ if ((DivMaskStats::maskChecks & mod) == 0) {
+ std::cerr << "**** DivMask stats (turn off by not defining macro) ****\n";
+ ColumnPrinter pr;
+ pr.addColumn(true, "* ");
+ pr.addColumn(false, " ");
+ pr.addColumn(false, " ");
+ pr.addColumn(true, " ");
+ pr[0] << "masks computed:\n";
+ pr[1] << ColumnPrinter::commafy(DivMaskStats::maskComputes) << '\n';
+ pr[2] << ColumnPrinter::percent
+ (DivMaskStats::maskComputes, DivMaskStats::maskChecks) << '\n';
+ pr[3] << "of mask checks\n";
+
+ pr[0] << "mask checks:\n";
+ pr[1] << ColumnPrinter::commafy(DivMaskStats::maskChecks) << '\n';
+ pr[2] << '\n';
+ pr[3] << '\n';
+
+ pr[0] << "mask hits:\n";
+ pr[1] << ColumnPrinter::commafy(DivMaskStats::maskHits) << '\n';
+ pr[2] << ColumnPrinter::percent
+ (DivMaskStats::maskHits, DivMaskStats::maskChecks) << '\n';
+ pr[3] << "of mask checks\n";
+
+ pr[0] << "mask div checks:\n";
+ pr[1] << ColumnPrinter::commafy(DivMaskStats::divChecks) << '\n';
+ pr[2] << ColumnPrinter::percent
+ (DivMaskStats::divChecks, DivMaskStats::maskChecks) << '\n';
+ pr[3] << "of mask checks\n";
+
+ pr[0] << "actually divide:\n";
+ pr[1] << ColumnPrinter::commafy(DivMaskStats::divDivides) << '\n';
+ pr[2] << ColumnPrinter::percent
+ (DivMaskStats::divDivides, DivMaskStats::divChecks) << '\n';
+ pr[3] << "of div checks\n";
+
+ pr[0] << "mask div hits:\n";
+ pr[1] << ColumnPrinter::commafy(DivMaskStats::divHits) << '\n';
+ pr[2] << ColumnPrinter::percent
+ (DivMaskStats::divHits, DivMaskStats::divChecks) << '\n';
+ pr[3] << "of div checks, " << ColumnPrinter::percent
+ (DivMaskStats::divHits,
+ DivMaskStats::divChecks - DivMaskStats::divDivides)
+ << " adjusted.\n";
+ std::cerr << pr << "****\n";
+ }
+#endif
+
+ return canDiv;
+ }
+
+ void combineAnd(const DivMask& mask) {_mask &= mask._mask;}
+
+ bool operator==(DivMask& mask) const {return _mask == mask._mask;}
+ bool operator!=(DivMask& mask) const {return _mask != mask._mask;}
+
+ /** Extender extends T with a div mask if UseDivMask is true. It is
+ allowed for T to be a reference type or const. */
+ template<class T, bool UseDivMask>
+ class Extender;
+
+ /** Base class to include a DivMask into a class at compile time
+ based on the template parameter UseDivMask. The class offers
+ the same methods either way, but they are replaced by do-nothing
+ or asserting versions if UseDivMask is false. */
+ template<bool UseDivMask>
+ class HasDivMask;
+
+ protected:
+ template<class C>
+ class ExponentComparer {
+ public:
+ ExponentComparer(size_t var, const C& conf): _var(var), _conf(conf) {}
+ template<class E>
+ bool operator()(const E& a, const E& b) const {
+ return _conf.getExponent(a, _var) < _conf.getExponent(b, _var);
+ }
+ private:
+ size_t _var;
+ const C& _conf;
+ };
+
+ struct VarData {
+ size_t var; // the variable in question
+
+ // let e be the average of the minimum and maximum exponent of var.
+ // then split is the number of elements whose exponent of var is
+ // <= average, or it is the number of elements whose exponent of var
+ // is > average, whichever is those two numbers is smaller.
+ size_t split;
+
+ // How many bits of the DivMask to dedicate to this variable.
+ size_t bitsForVar;
+
+ bool operator<(const VarData& data) const {
+ return split > data.split; // larger split first in order
+ }
+ };
+
+ typedef unsigned int MaskType;
+ DivMask(MaskType mask): _mask(mask) {}
+
+ private:
+ /** To eliminate warnings about T& if T is already a reference type. */
+ template<class T> struct Ref {typedef T& RefType;};
+ template<class T> struct Ref<T&> {typedef T& RefType;};
+ MaskType _mask;
+ };
+
+ template<class C>
+ class DivMask::Calculator<C, true> {
+ public:
+ Calculator(const C& conf) {rebuildDefault(conf);}
+
+ /** Change the meaning of the bits in the div masks produced by this
+ object to something that will likely work well for entries
+ in [begin, end). All div masks will have to be recomputed
+ after this. Mixing div masks computed before a call to
+ rebuild() with ones after has unpredictable results. */
+ template<class Iter>
+ void rebuild(Iter begin, Iter end, const C& conf);
+
+ /** Rebuilds without the benefit of knowing a range of entries
+ that the div masks are supposed to work well for. */
+ void rebuildDefault(const C& conf);
+
+ /** Computes a div mask for t. */
+ template<class T>
+ DivMask::MaskType compute(const T& t, const C& conf) const;
+
+ private:
+ typedef typename C::Exponent Exponent;
+ /** If entry at index i is the pair (var,exp) then the bit at
+ index var in a bit mask is 1 if the exponent of var in the
+ monomial is strictly greater than exp. */
+ typedef std::vector<std::pair<size_t, Exponent> > BitContainer;
+ BitContainer _bits;
+ };
+
+ template<class C>
+ template<class Iter>
+ void DivMask::Calculator<C, true>::
+ rebuild(Iter begin, Iter end, const C& conf) {
+ const size_t size = std::distance(begin, end);
+ if (size == 0) {
+ rebuildDefault(conf);
+ return;
+ }
+
+ _bits.clear();
+ const size_t varCount = conf.getVarCount();
+ const size_t TotalBits = sizeof(MaskType) * BitsPerByte;
+
+ // ** Determine information about each variable
+ std::vector<VarData> datas;
+ for (size_t var = 0; var < varCount; ++var) {
+ Exponent min = conf.getExponent(*begin, 0);
+ Exponent max = min;
+ for (Iter it = begin; it != end; ++it) {
+ Exponent exp = conf.getExponent(*it, var);
+ if (max < exp)
+ max = exp;
+ if (exp < min)
+ min = exp;
+ }
+ Exponent average = min + (max - min) / 2; // this formula avoids overflow
+ size_t split = 0;
+ for (Iter it = begin; it != end; ++it)
+ if (conf.getExponent(*it, var) < average)
+ ++split;
+ if (split > size / 2)
+ split = size - split;
+ VarData data;
+ data.var = var;
+ data.split = split;
+ datas.push_back(data);
+ }
+ std::sort(datas.begin(), datas.end());
+ MATHIC_ASSERT(datas.size() == varCount);
+
+ // distribute bits to variables according to the data collected
+ std::vector<size_t> bitsForVars(varCount);
+ for (size_t i = 0; i < varCount; ++i) {
+ const size_t var = datas[i].var;
+ bitsForVars[var] = TotalBits / varCount;
+ if (i < TotalBits % varCount)
+ ++bitsForVars[var];
+ }
+
+ // calculate the meaning of each bit and put it in _bits
+ for (size_t var = 0; var < varCount; ++var) {
+ const size_t bitsForVar = bitsForVars[var];
+ if (bitsForVar == 0)
+ continue;
+
+ const bool useRank = false;
+ if (useRank) {
+ std::sort(begin, end, ExponentComparer<C>(var, conf));
+ size_t size = std::distance(begin, end);
+ size_t offset = size / (bitsForVar + 1);
+ if (offset== 0)
+ offset = 1;
+ Exponent lastExp;
+ size_t lastJ = 0;
+ for (size_t i = 1; i <= bitsForVar; ++i) {
+ size_t j = i * offset;
+ if (i > 1 && j < lastJ)
+ j = lastJ + 1;
+ if (j >= size)
+ j = size - 1;
+ if (i > 1) {
+ while (j < size && conf.getExponent(begin[j], var) == lastExp)
+ ++j;
+ if (j == size)
+ break;
+ }
+ _bits.push_back(
+ std::make_pair(var, conf.getExponent(begin[j], var)));
+ lastJ = j;
+ lastExp = conf.getExponent(begin[j], var);
+ if (j == size - 1)
+ break;
+ }
+ } else {
+ Exponent min = conf.getExponent(*begin, 0);
+ Exponent max = min;
+ for (Iter it = begin; it != end; ++it) {
+ Exponent exp = conf.getExponent(*it, var);
+ if (max < exp)
+ max = exp;
+ if (exp < min)
+ min = exp;
+ }
+
+ // divide the range [a,b] into bitsForVar equal pieces
+ // and use the left end points of those ranges
+ // as the points for the bits.
+ Exponent increment = (max - min) / static_cast<Exponent>(bitsForVar); // todo: can avoid cast?
+ if (increment == 0)
+ increment = 1;
+ for (size_t i = 0; i < bitsForVar; ++i)
+ _bits.push_back(std::make_pair(var, min + increment * static_cast<Exponent>(i)));
+ // todo: can avoid cast?
+ }
+ }
+ }
+
+ template<class C>
+ void DivMask::Calculator<C, true>::
+ rebuildDefault(const C& conf) {
+ _bits.clear();
+ const size_t varCount = conf.getVarCount();
+ const size_t TotalBits = sizeof(MaskType) * BitsPerByte;
+ for (size_t var = 0; var < varCount; ++var) {
+ const size_t bitsForVar =
+ TotalBits / varCount + (var < TotalBits % varCount);
+ Exponent exp = 0;
+ for (size_t i = 0; i < bitsForVar; ++i) {
+ _bits.push_back(std::make_pair(var, exp));
+ exp = (i == 0 ? 1 : exp * 2);
+ }
+ }
+ }
+
+ template<class C>
+ template<class T>
+ DivMask::MaskType DivMask::Calculator<C, true>::
+ compute(const T& t, const C& conf) const {
+#ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO
+ ++DivMaskStats::maskComputes;
+#endif
+ typedef typename BitContainer::const_iterator const_iterator;
+ const const_iterator end = _bits.end();
+ DivMask::MaskType mask = 0;
+ for (const_iterator it = _bits.begin(); it != end; ++it)
+ mask = (mask << 1) | (conf.getExponent(t, it->first) > it->second);
+ return mask;
+ }
+
+ template<class C>
+ class DivMask::Calculator<C, false> {
+ public:
+ Calculator(const C& conf) {}
+
+ template<class Iter>
+ void rebuild(Iter begin, Iter end, const C& conf) {}
+ void rebuildDefault(const C& conf) {}
+ };
+
+ template<>
+ class DivMask::HasDivMask<true> {
+ public:
+ template<class T, class C>
+ HasDivMask(const T& t, const Calculator<C>& calc, const C& conf):
+ _mask(t, calc, conf) {}
+ HasDivMask() {resetDivMask();}
+
+ DivMask& getDivMask() {return _mask;}
+ const DivMask& getDivMask() const {return _mask;}
+ void resetDivMask() {_mask = DivMask::getMaxMask();}
+ bool canDivide(const HasDivMask<true>& t) const {
+ return getDivMask().canDivide(t.getDivMask());
+ }
+
+ void updateToLowerBound(const HasDivMask<true>& t) {
+ _mask.combineAnd(t.getDivMask());
+ }
+
+ protected:
+ template<class T, class C>
+ void recalculateDivMask
+ (const T& t, const Calculator<C>& calc, const C& conf) {
+ _mask.recalculate(t, calc, conf);
+ }
+
+ private:
+ DivMask _mask;
+ };
+
+ template<>
+ class DivMask::HasDivMask<false> {
+ public:
+ void resetDivMask() {MATHIC_ASSERT(false);}
+ DivMask getDivMask() const {MATHIC_ASSERT(false); return DivMask();}
+ bool canDivide(const HasDivMask<false>& t) const {return true;}
+ template<bool B>
+ void updateToLowerBound(const HasDivMask<B>& entry) {}
+ };
+
+ template<class T>
+ class DivMask::Extender<T, true> : public HasDivMask<true> {
+ private:
+ typedef typename Ref<T>::RefType Reference;
+ typedef typename Ref<const T>::RefType ConstReference;
+ public:
+ Extender(): HasDivMask<true>(), _t() {}
+ template<class C>
+ Extender(ConstReference t, const Calculator<C>& calc, const C& conf):
+ HasDivMask<true>(t, calc, conf), _t(t) {}
+
+ template<class S, class C>
+ bool divides(const Extender<S, true>& t, const C& conf) const {
+ bool canDiv = this->canDivide(t);
+#ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO
+ ++DivMaskStats::divChecks;
+ if (!canDiv)
+ ++DivMaskStats::divHits;
+#endif
+ if (!canDiv)
+ return false;
+
+ bool actuallyDivides = conf.divides(get(), t.get());
+#ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO
+ if (actuallyDivides)
+ ++DivMaskStats::divDivides;
+#endif
+ return actuallyDivides;
+ }
+
+ template<class C>
+ void recalculateDivMask(const Calculator<C>& calc, const C& conf) {
+ this->HasDivMask<true>::recalculateDivMask(get(), calc, conf);
+ }
+
+ Reference get() {return _t;}
+ ConstReference get() const {return _t;}
+
+ private:
+ T _t;
+ };
+
+ template<class T>
+ class DivMask::Extender<T, false> : public HasDivMask<false> {
+ private:
+ typedef typename Ref<T>::RefType Reference;
+ typedef typename Ref<const T>::RefType ConstReference;
+ public:
+ Extender(): HasDivMask<false>(), _t() {}
+ template<class C>
+ Extender(ConstReference t, const Calculator<C>& calc, const C& conf):
+ HasDivMask<false>(), _t(t) {}
+
+ template<class S, class C>
+ bool divides(const Extender<S, false>& t, const C& conf) const {
+ return conf.divides(get(), t.get());
+ }
+
+ template<class C>
+ void recalculateDivMask(const Calculator<C>& calc, const C& conf) {}
+
+ Reference get() {return _t;}
+ ConstReference get() const {return _t;}
+
+ private:
+ T _t;
+ };
+}
+
+#endif
diff --git a/src/mathic/ElementDeleter.cpp b/src/mathic/ElementDeleter.cpp
new file mode 100755
index 0000000..fe8d951
--- /dev/null
+++ b/src/mathic/ElementDeleter.cpp
@@ -0,0 +1 @@
+#include "ElementDeleter.h"
diff --git a/src/mathic/ElementDeleter.h b/src/mathic/ElementDeleter.h
new file mode 100755
index 0000000..9de80ab
--- /dev/null
+++ b/src/mathic/ElementDeleter.h
@@ -0,0 +1,138 @@
+#ifndef MATHIC_ELEMENT_DELETER_GUARD
+#define MATHIC_ELEMENT_DELETER_GUARD
+
+#include "stdinc.h"
+#include <memory>
+
+namespace mathic {
+ // The purpose of this class is to call delete on the elements of a
+ // standard library container which holds pointers. It removes the
+ // elements from the container as they are being deleted, but it does
+ // not delete the container itself. Do not use this class to
+ // deallocate a vector of built-in arrays, since those require
+ // deallocation using delete[] rather than delete.
+ //
+ // This can be a convenience when coding, but the real purpose is to
+ // avoid memory leaks in the face of an exception being thrown. When a
+ // standard library container goes out of scope, its destructor is
+ // called, but the destructor does not deallocate pointer elements, so
+ // they will leak unless special care is taken to avoid that, such as
+ // using this class.
+ //
+ // The most straight-forward solution may seem to use
+ // e.g. vector<auto_ptr<T>> in place of vector<T*>, but this does not
+ // work because storing auto_ptr<T> in a standard library container is
+ // never safe (look this up on the internet to get the details).
+ //
+ // The reference counting smart pointer class shared_ptr from Boost or
+ // TR1 would solve this issue even better by using
+ // vector<shared_ptr<T>> instead of vector<T*>, but that would require
+ // a dependency on Boost or on having a very recent compiler which
+ // incorporates TR1.
+ //
+ // TODO: make an AutoVector that wraps std::vector instead of or as a
+ // supplement to this class.
+ //
+ // Container::value_type is required to be a pointer type.
+ template<class Container>
+ class ElementDeleter {
+ public:
+ // Only the constructor can attach an ElementDeleter to a container,
+ // and this helps ensure (but does not guarantee) the precondition
+ // of the destructor of ElementDeleter.
+ ElementDeleter(Container& container): _container(&container) {
+ }
+
+ // Calls deleteElements() and shares its precondition.
+ ~ElementDeleter() {
+ deleteElements();
+ }
+
+ // Call release() to prevent this ElementDeleter from manipulating
+ // the container in any way.
+ void release() {
+ _container = 0;
+ }
+
+ // If release has been called, this method does nothing. Otherwise
+ // the container must still be valid, and then delete is called on
+ // each element of the array and clear is called on the container.
+ void deleteElements() {
+ if (_container == 0)
+ return;
+
+ // The code below may seem obviously correct, but it is a
+ // non-trivial fact that it works in the face of exceptions.
+ //
+ // First of all, we are allowed to assume that destructors do not
+ // throw exceptions, so the loop will run to completion.
+ //
+ // Normally clear() *can* throw an exception according to the
+ // standard (which is weird), but if the copy constructor and
+ // assignment operator do not throw exceptions, then it does
+ // not. In our case, we require the element type to be a pointer
+ // type, so for this reason only do we know that clear will not
+ // throw an exception. Thus we do not have to worry about leaving
+ // around a container full of invalid pointers if clear() should
+ // throw an exception.
+
+ typename Container::iterator end = _container->end();
+ typename Container::iterator it = _container->begin();
+ for (; it != end; ++it)
+ delete *it;
+ _container->clear();
+ }
+
+ private:
+ Container* _container;
+ };
+
+ // exceptionSafePushBack is designed to work around the fact that this
+ // code can leak memory:
+ //
+ // vector<int*> vec;
+ // ElementDeleter<vector<int*> > elementDeleter(vec);
+ // auto_ptr<int> p(new int());
+ // vec.push_back(p.release())
+ //
+ // This is because push_back can fail by throwing a bad_alloc, and at
+ // that point the pointer in p has already been released, so that
+ // pointer is now lost and hence the memory is leaked.
+ //
+ // This can be fixed by replacing
+ //
+ // vec.push_back(p.release())
+ //
+ // by
+ //
+ // vec.push_back(0);
+ // vec.back() = p.release();
+ //
+ // but this is annoying and looks quite strange. It is much clearer to
+ // write
+ //
+ // exceptionSafePushBack(vec, p);
+ //
+ template<class Container, class Element>
+ void exceptionSafePushBack(Container& container, std::auto_ptr<Element> pointer) {
+ container.push_back(0);
+ container.back() = pointer.release();
+ }
+
+ // Serves the same purpose as exceptionSafePushBack, except that this
+ // overload will simply ignore an exception without propagating it.
+ // Thus if there is not enough memory to add the element to the container,
+ // the element will simply get deleted and the container will remain
+ // unchanged. This works well if e.g. adding an element to a cache, where
+ // it is no great problem if the element gets deleted rather than added.
+ template<class Container, class Element>
+ void noThrowPushBack(Container& container, std::auto_ptr<Element> pointer) throw () {
+ try {
+ exceptionSafePushBack(container, pointer);
+ } catch (const std::bad_alloc&) {
+ // Ignore the exception.
+ }
+ }
+}
+
+#endif
diff --git a/src/mathic/GeoFront.h b/src/mathic/GeoFront.h
new file mode 100644
index 0000000..9fc145a
--- /dev/null
+++ b/src/mathic/GeoFront.h
@@ -0,0 +1,375 @@
+#ifndef MATHIC_GEO_FRONT_GUARD
+#define MATHIC_GEO_FRONT_GUARD
+
+#include "stdinc.h"
+#include <vector>
+#include <utility>
+
+namespace mathic {
+ /**
+ To be used by Geobucket class.
+
+ Configuration is the Configuration from the owning Geobucket.
+
+ Bucket is the Bucket class from the owning Geobucket. Having Bucket be a
+ parameter allows it to be used before it is declared so that this header
+ need not include Geobucket's header, which would otherwise be a cyclic
+ dependency. This also grants access to Geobucket<C>::Bucket which is
+ otherwise private.
+
+ Why not make this an inner template class of Geobucket? Because inner
+ template classes cannot be specialized without also specializing the
+ outer class.
+ */
+
+ template<class Configuration>
+ class Geobucket;
+
+ template<class Configuration,
+ class Bucket = typename Geobucket<Configuration>::Bucket,
+ bool Order = Configuration::trackFront>
+ class GeoFront;
+
+ // ********************************************************************
+ // GeoFront maintaining no special order
+ template<class C, class Bucket>
+ class GeoFront<C, Bucket, false> {
+ public:
+ /** A reference is kept to entryCountRef so that it can be updated
+ in the event of a deduplication. */
+ GeoFront(const C& conf, size_t& entryCountRef):
+ _cachedMaxBucket(0), _entryCountRef(entryCountRef), _conf(conf) {
+ MATHIC_ASSERT(!C::trackFront);
+ }
+
+ void clear() {
+ _cachedMaxBucket = 0;
+ }
+
+ void reserveCapacity(size_t newCapacity) {}
+ void bucketsInvalidated(Bucket* oldBegin, Bucket* newBegin) {
+ _cachedMaxBucket = 0;
+ }
+ bool empty() const {return _entryCountRef == 0;}
+
+ void insert(Bucket* bucket) {_cachedMaxBucket = 0;}
+ void remove(Bucket* bucket) {_cachedMaxBucket = 0;}
+ void keyIncreased(Bucket* bucket) {_cachedMaxBucket = 0;}
+ void keyDecreased(Bucket* bucket) {_cachedMaxBucket = 0;}
+ void swapKeys(Bucket* a, Bucket* b) {}
+ bool larger(const Bucket* a, const Bucket* b) const {
+ MATHIC_ASSERT(false);
+ return false;
+ }
+ const Bucket* getMax(Bucket* bucketBegin, Bucket* bucketEnd) const;
+
+#ifdef MATHIC_DEBUG
+ bool debugIsValid(Bucket* bucketBegin, Bucket* bucketEnd) const;
+#endif
+
+ size_t getMemoryUse() const;
+
+ private:
+ const Bucket* computeMax(Bucket* bucketBegin, Bucket* bucketEnd) const;
+
+ mutable const Bucket* _cachedMaxBucket;
+ mutable size_t& _entryCountRef;
+ const C& _conf;
+ };
+
+ template<class C, class B>
+ size_t GeoFront<C, B, false>::getMemoryUse() const {
+ return 0;
+ }
+
+ template<class C, class B>
+ const B* GeoFront<C, B, false>::getMax(B* bucketBegin, B* bucketEnd) const {
+ // the point is that the compiler is more likely to compile this
+ // pre-calculation so that computeMax won't get called in cases
+ // where the maximum has already been computed.
+ if (_cachedMaxBucket != 0)
+ return _cachedMaxBucket;
+ return computeMax(bucketBegin, bucketEnd);
+ }
+
+ template<class C, class B>
+ const B* GeoFront<C, B, false>::computeMax
+ (B* bucketBegin, B* bucketEnd) const {
+ MATHIC_ASSERT(_cachedMaxBucket == 0);
+ const B* maxBucket = bucketBegin;
+ while (maxBucket->empty()) {
+ ++maxBucket;
+ MATHIC_ASSERT(maxBucket != bucketEnd);
+ }
+ for (const B* it = maxBucket + 1; it != bucketEnd; ++it) {
+ if (it->empty())
+ continue;
+ typename C::CompareResult cmp =
+ _conf.compare(it->back(), maxBucket->back());
+ if (_conf.cmpLessThan(cmp))
+ continue;
+ if (C::supportDeduplication && _conf.cmpEqual(cmp)) {
+ B* mb = const_cast<B*>(maxBucket);
+ mb->setEntry(mb->end() - 1,
+ _conf.deduplicate(mb->back(), it->back()));
+ const_cast<B*>(it)->pop_back();
+ --_entryCountRef;
+ continue;
+ }
+ maxBucket = it;
+ }
+ MATHIC_ASSERT(maxBucket != bucketEnd);
+ return _cachedMaxBucket = maxBucket;
+ }
+
+#ifdef MATHIC_DEBUG
+ template<class C, class B>
+ bool GeoFront<C, B, false>::debugIsValid(B* bucketBegin, B* bucketEnd) const {
+ if (_cachedMaxBucket == 0)
+ return true;
+ MATHIC_ASSERT(!_cachedMaxBucket->empty());
+ for (B* bucket = bucketBegin; bucket != bucketEnd; ++bucket) {
+ if (!bucket->empty()) {
+ MATHIC_ASSERT(!_conf.cmpLessThan
+ (_conf.compare(_cachedMaxBucket->back(), bucket->back())));
+ }
+ }
+ return true;
+ }
+#endif
+
+ // ********************************************************************
+ // GeoFront maintaining an ordered list
+ template<class C, class Bucket>
+ class GeoFront<C, Bucket, true> {
+ public:
+ GeoFront(const C& conf, size_t& entryCountRef);
+
+ Bucket** begin() {return _bucketBegin;}
+ Bucket*const* begin() const {return _bucketBegin;}
+ Bucket** end() {return _bucketEnd;}
+ Bucket*const* end() const {return _bucketEnd;}
+
+ /** Can contain this many */
+ void reserveCapacity(size_t newCapacity);
+ void bucketsInvalidated(Bucket* oldBegin, Bucket* newBegin);
+ bool empty() const {return _bucketBegin == _bucketEnd;}
+
+ void clear();
+ void insert(Bucket* bucket);
+ void remove(Bucket* bucket);
+ void keyIncreased(Bucket* bucket);
+ void keyDecreased(Bucket* bucket);
+ void swapKeys(Bucket* a, Bucket* b);
+ bool larger(const Bucket* a, const Bucket* b) const;
+ const Bucket* getMax(Bucket* bucketBegin, Bucket* bucketEnd) const;
+
+#ifdef MATHIC_DEBUG
+ bool debugIsValid(Bucket* bucketBegin, Bucket* bucketEnd) const;
+#endif
+
+ size_t getMemoryUse() const;
+
+ private:
+ size_t size() const {return _bucketEnd - _bucketBegin;}
+ size_t capacity() const {return _bucketCapacityEnd - _bucketBegin;}
+
+ Bucket** _bucketBegin;
+ Bucket** _bucketEnd;
+ Bucket** _bucketCapacityEnd;
+ mutable size_t& _entryCountRef;
+ const C& _conf;
+ };
+
+ template<class C, class B>
+ void GeoFront<C, B, true>::clear() {
+ _bucketEnd = _bucketBegin;
+ }
+
+ template<class C, class B>
+ size_t GeoFront<C, B, true>::getMemoryUse() const {
+ return capacity() * sizeof(*_bucketBegin);
+ }
+
+ template<class C, class B>
+ GeoFront<C, B, true>::GeoFront(const C& conf, size_t& entryCountRef):
+ _bucketBegin(0),
+ _bucketEnd(0),
+ _bucketCapacityEnd(0),
+ _entryCountRef(entryCountRef),
+ _conf(conf) {
+ MATHIC_ASSERT(C::trackFront);
+ }
+
+ template<class C, class B>
+ void GeoFront<C, B, true>::reserveCapacity(size_t newCapacity) {
+ ASSERT(newCapacity >= size());
+ if (newCapacity == 0)
+ newCapacity = 1;
+ size_t const oldSize = size();
+ B** const oldBegin = _bucketBegin;
+ B** const oldEnd = _bucketEnd;
+ _bucketBegin = new B*[newCapacity];
+ _bucketEnd = _bucketBegin + oldSize;
+ _bucketCapacityEnd = _bucketBegin + newCapacity;
+ std::copy(oldBegin, oldEnd, _bucketBegin);
+
+ // the tokens point into the old space, so map them to an index
+ // and then back to a pointer into the newly allocated memory.
+ for (B** bucket = _bucketBegin; bucket != _bucketEnd; ++bucket) {
+ B** token = (*bucket)->getFrontToken();
+ token = (token - oldBegin) + _bucketBegin;
+ (*bucket)->setFrontToken(token);
+ }
+ delete[] oldBegin;
+ }
+
+ template<class C, class B>
+ void GeoFront<C, B, true>::bucketsInvalidated
+ (B* oldBegin, B* newBegin) {
+ // _buckets points into an array of buckets that has been reallocated,
+ // so we need to go to an index and back to update the pointers
+ // to point into the new memory area.
+ if (empty())
+ return;
+ for (B** bucket = begin(); bucket != end(); ++bucket)
+ *bucket = (*bucket - oldBegin) + newBegin;
+ }
+
+ template<class C, class B>
+ void GeoFront<C, B, true>::insert(B* bucket) {
+ if (!C::trackFront)
+ return;
+ MATHIC_ASSERT(bucket != 0);
+ MATHIC_ASSERT(bucket->_frontPos == 0);
+ MATHIC_ASSERT(!bucket->empty());
+ if (_bucketEnd == _bucketCapacityEnd)
+ reserveCapacity(size() + 1);
+ *_bucketEnd = bucket;
+ ++_bucketEnd;
+ bucket->_frontPos = end() - 1;
+ keyIncreased(bucket);
+ }
+
+ template<class C, class B>
+ void GeoFront<C, B, true>::keyIncreased(B* bucket) {
+ B** pos = bucket->_frontPos;
+ B** begin = this->begin();
+ for (; pos != begin; --pos) { // move bucket to lower index
+ B& shouldBeGreater = **(pos - 1);
+ typename C::CompareResult cmp =
+ _conf.compare(shouldBeGreater.back(), bucket->back());
+ if (!_conf.cmpLessThan(cmp))
+ break;
+ // todo: if equal
+ *pos = *(pos - 1);
+ shouldBeGreater._frontPos = pos;
+ }
+ // We don't have to adjust bucket's position if it never moved, but
+ // detecting that without extra branches makes the code too complex
+ // for it to be worth it.
+ *pos = bucket;
+ bucket->_frontPos = pos;
+ }
+
+ template<class C, class B>
+ void GeoFront<C, B, true>::keyDecreased(B* bucket) {
+ if (bucket->empty()) {
+ remove(bucket);
+ return;
+ }
+ B** pos = bucket->_frontPos;
+ B** end = this->end();
+ for (; pos + 1 != end; ++pos) { // move bucket to higher index
+ B& otherBucket = **(pos + 1);
+ typename C::CompareResult cmp =
+ _conf.compare(bucket->back(), otherBucket.back());
+ if (!_conf.cmpLessThan(cmp)) {
+ if (!C::supportDeduplication || !_conf.cmpEqual(cmp))
+ break; // greater than, found correct position
+ otherBucket.setEntry(otherBucket.end() - 1,
+ _conf.deduplicate(bucket->back(), otherBucket.back()));
+ bucket->pop_back();
+ --_entryCountRef;
+ if (bucket->empty()) {
+ bucket->_frontPos = pos;
+ remove(bucket);
+ return;
+ }
+ }
+ *pos = *(pos + 1);
+ otherBucket._frontPos = pos;
+ }
+ // We don't have to adjust bucket's position if it never moved, but
+ // detecting that without extra branches makes the code too complex
+ // for it to be worth it.
+ *pos = bucket;
+ bucket->_frontPos = pos;
+ }
+
+ template<class C, class B>
+ void GeoFront<C, B, true>::remove(B* bucket) {
+ MATHIC_ASSERT(bucket->_frontPos != 0);
+ MATHIC_ASSERT(bucket->empty());
+ B** end = this->end(); // can't dereference end
+ for (B** i = bucket->_frontPos + 1; i != end; ++i) {
+ *(i - 1) = *i;
+ (*i)->_frontPos = i - 1;
+ }
+ --_bucketEnd;
+ bucket->_frontPos = 0;
+ }
+
+ template<class C, class B>
+ void GeoFront<C, B, true>::swapKeys(B* a, B* b) {
+ MATHIC_ASSERT(a != 0);
+ MATHIC_ASSERT(b != 0);
+ std::swap(a->_frontPos, b->_frontPos);
+ if (a->_frontPos != 0)
+ *a->_frontPos = a;
+ if (b->_frontPos != 0)
+ *b->_frontPos = b;
+ }
+
+ template<class C, class B>
+ bool GeoFront<C, B, true>::larger(const B* a, const B* b) const {
+ MATHIC_ASSERT(a != 0);
+ MATHIC_ASSERT(b != 0);
+ return a->_frontPos < b->_frontPos;
+ }
+
+ template<class C, class B>
+ const B* GeoFront<C, B, true>::getMax(B* bucketBegin, B* bucketEnd) const {
+ MATHIC_ASSERT(!empty());
+ return *begin();
+ }
+
+#ifdef MATHIC_DEBUG
+ template<class C, class B>
+ bool GeoFront<C, B, true>::debugIsValid(B* bucketBegin, B* bucketEnd) const {
+ std::vector<const B*> nonEmpty;
+ size_t size = bucketEnd - bucketBegin;
+ for (size_t b = 0; b < size; ++b) {
+ if (bucketBegin[b].empty()) {
+ MATHIC_ASSERT(bucketBegin[b]._frontPos == 0);
+ } else {
+ MATHIC_ASSERT(bucketBegin[b]._frontPos != 0);
+ MATHIC_ASSERT(*(bucketBegin[b]._frontPos) == &(bucketBegin[b]));
+ nonEmpty.push_back(&(bucketBegin[b]));
+ }
+ }
+ std::vector<B*> frontCopy(_bucketBegin, _bucketEnd);
+ std::sort(nonEmpty.begin(), nonEmpty.end());
+ std::sort(frontCopy.begin(), frontCopy.end());
+ MATHIC_ASSERT(std::equal(frontCopy.begin(), frontCopy.end(), nonEmpty.begin()));
+ if (!empty()) {
+ for (B** it = _bucketBegin + 1; it != _bucketEnd; ++it)
+ MATHIC_ASSERT(!_conf.cmpLessThan
+ (_conf.compare((*(it - 1))->back(), (*it)->back())));
+ }
+ return true;
+ }
+#endif
+}
+
+#endif
diff --git a/src/mathic/Geobucket.h b/src/mathic/Geobucket.h
new file mode 100755
index 0000000..c14ea9c
--- /dev/null
+++ b/src/mathic/Geobucket.h
@@ -0,0 +1,805 @@
+#ifndef MATHIC_GEOBUCKET_GUARD
+#define MATHIC_GEOBUCKET_GUARD
+
+#include "stdinc.h"
+#include <string>
+#include <sstream>
+#include <vector>
+#include <algorithm>
+#include "GeoFront.h"
+
+namespace mathic {
+ enum GeobucketBucketStorage {
+ GeoStorePlain = 0,
+ GeoStoreDoubleBuffer = 1,
+ GeoStoreSameSizeBuffer = 2,
+
+ GeobucketBucketStorageBegin = 0,
+ GeobucketStorageEnd = 3
+ };
+
+ /** A geobucket priority queue.
+
+ The Configuration template parameter specifies properties of the geobucket.
+ A configuration object is passed to the constructor of geobucket which
+ makes a copy. After the initial copy no further copies are made.
+
+ Configuration must have these fields:
+
+ * A type Entry
+ The elements of the geobucket will have this type. Entry must have a copy
+ constructor.
+
+ * A type CompareResult
+ Intended to be a bool for "less than" or some other type that can encode
+ "less than", "equal" and "greater than". As the Configuration itself
+ interprets what the values of this type mean, the type can be anything.
+ CompareResult must have a copy constructor.
+
+ * A const or static method: CompareResult compare(Entry, Entry)
+ It is OK for the two parameters to be const Entry&, but compare must not
+ retain a reference to the Entry. The return value is intended to
+ encode the ordering of the two elements.
+
+ * A const or static method: bool cmpLessThan(CompareResult)
+ The geobucket calls this on a CompareResult returned from compare(a,b).
+ The return value should be true if and only if a is strictly less than b.
+
+ * A size_t minBucketSize
+ This is the size of the smallest bucket. Must be at least 1.
+
+ * A size_t geoBase
+ When a new bucket is added, its capacity is geoBase multiplied by the
+ largest capacity among the buckets in the geobucket. Must be at least
+ two.
+
+ * A static const size_t insertFactor
+ An insert of size S will be done into the smallest bucket whose total
+ capacity (not free capacity) is at least S * insertFactor.
+
+ * A static const bool supportDeduplication
+ If this is true, then the geobucket will remove entries that are compared
+ and found to be equal. This requires the use of a method cmpEqual and
+ deduplicate.
+
+ * A static or const method: bool cmpEqual(CompareResult)
+ The method is only called if supportDeduplication is true.
+ The geobucket calls this on a CompareResult returned from compare(a,b).
+ If the return value is true, then a and b must be equivalent in the ordering
+ imposed by compare and cmpLessThan. When the return value is true,
+ the two elements will be replaced by the return value of deduplicate.
+
+ * A static or const method: Entry deduplicate(Entry a, Entry b)
+ This method is only called if supportDeduplication is true and
+ cmpEqual(compare(a,b)) is true. The two elements a and b in the geobucket
+ will be replaced by the return value of deduplicate. So the number of
+ elements in the geobucket will decrease by one every time deduplicate
+ is called.
+
+ * A static const bool minBucketBinarySearch
+ If this field is true, insertions of single elements is done using binary
+ search. Otherwise a linear search is done.
+
+ * A static const bool trackFront
+ If this field is true, then a sorted list of buckets will be maintained
+ to aid in determining the largest element in the queue. Otherwise a
+ linear search is done through the buckets to find the largest element.
+
+ * A static const bool premerge
+ Let A be a list of elements and let B be the elements in a bucket. Suppose
+ we are about to merge A and B and put them into the same bucket. If
+ the combined size of A and B is larger than the capacity of the bucket,
+ and premerge is true, then B will be preemptively merged into the next
+ bucket after which A can be copied into the now empty bucket that B
+ previously occupied. If premerge is false, then A and B will be merged,
+ and the overflow will force a merge of the combined A and B into the
+ next bucket.
+
+ * A static const bool collectMax
+ The meta data of a bucket is kept in a separate memory area from the
+ elements of the bucket. If collectMax is true, then the maximum element
+ of each bucket is copied into the meta data area. The idea is to
+ minimize cache misses caused when pop does a linear scan through
+ the maximum elements.
+
+ * A static const GeobucketBucketStorage bucketStorage
+ GeoStorePlain = 0,
+ GeoStoreDoubleBuffer = 1,
+ GeoStoreSameSizeBuffer = 2,
+
+ If this field is GeoStorePlain, then a bucket of capacity S has a memory
+ area of size S.
+
+ If this field is GeoStoreDoubleBuffer, then every bucket will have two
+ same-size memory areas. Only one of the two memory areas is in use at
+ any one time. That way a merge into the bucket can store its
+ result into the other memory area so that a merge does not require a copy.
+
+ If this field is GeoStoreSameSizeBuffer, then all buckets use a
+ memory area of the same size as the maximum bucket. A bucket's noted
+ capacity does not change. This way any memory area can be used in place
+ of any other memory area, which makes it possible to do merges with no
+ copies and also the content of two buckets can be swapped with no copies.
+ Cannot be combined with useDoubleBucket.
+ */
+ template<class C>
+ class Geobucket {
+ public:
+ typedef C Configuration;
+ typedef typename Configuration::Entry Entry;
+
+ Geobucket(const Configuration& configuration);
+
+ Configuration& getConfiguration() {return _conf;}
+ const Configuration& getConfiguration() const {return _conf;}
+
+ std::string getName() const;
+ void push(Entry entries);
+
+ // [begin, end) must be sorted in decreasing order.
+ // If Configuration::supportDeduplication is true, then no value must
+ // be present twice in [begin, end).
+ template<class It>
+ void push(It begin, It end);
+ void clear();
+ Entry pop();
+ Entry top() const;
+ bool empty() const;
+ void print(std::ostream& out) const;
+
+ template<class T>
+ void forAll(T& t) const {
+ for (Bucket* bucket = _bucketBegin; bucket != _bucketEnd; ++bucket) {
+ const Entry* stop = bucket->end();
+ for (const Entry* entry = bucket->begin(); entry != stop; ++entry) {
+ if (!t.proceed(*entry)) {
+ MATHIC_ASSERT(isValid());
+ return;
+ }
+ }
+ }
+ MATHIC_ASSERT(isValid());
+ }
+
+ size_t getMemoryUse() const;
+
+ private:
+ Geobucket(const Geobucket&); // unavailable
+ Geobucket& operator=(const Geobucket&); // unavailable
+
+ struct Bucket {
+ Bucket(size_t capacity, Entry* buffer, Entry* otherBuffer);
+ size_t size() const {return _size;}
+ size_t capacity() const {return _capacity;}
+ Entry* begin() {return _begin;}
+ Entry* end() {return begin() + size();}
+ const Entry* begin() const {return _begin;}
+ const Entry* end() const {return begin() + size();}
+ bool empty() const {return size() == 0;}
+ const Entry& back() const {
+ MATHIC_ASSERT(!empty());
+ return Configuration::collectMax ? _back : *(end() - 1);
+ }
+ const Entry& operator[](size_t i) const {
+ MATHIC_ASSERT(i < size());
+ return *(begin() + i);
+ }
+ void pop_back() {
+ MATHIC_ASSERT(size() > 0);
+ --_size;
+ if (Configuration::collectMax && _size > 0)
+ _back = *(end() - 1);
+ }
+ void setEntry(Entry* pos, const Entry& entry) {
+ MATHIC_ASSERT(begin() <= pos && pos < end());
+ *pos = entry;
+ if (Configuration::collectMax && pos == end() - 1)
+ _back = entry;
+ }
+ void insertAtNotEnd(Entry* pos, const Entry& entry) {
+ MATHIC_ASSERT(begin() <= pos && pos < end());
+ for (Entry* it = end(); it != pos; --it)
+ *it = *(it - 1);
+ *pos = entry;
+ ++_size;
+ }
+ void setBuffer(Entry* buffer) {
+ std::copy(begin(), end(), buffer);
+ _begin = buffer;
+ }
+ void setBufferWithNewEntries(Entry* buffer, size_t size) {
+ _begin = buffer;
+ _size = size;
+ if (size > 0)
+ _back = *(end() - 1);
+ }
+ void setOtherBuffer(Entry* otherBuffer) {
+ MATHIC_ASSERT(Configuration::bucketStorage == GeoStoreDoubleBuffer);
+ _otherBuffer = otherBuffer;
+ }
+ Entry* getOtherBuffer() {
+ MATHIC_ASSERT(Configuration::bucketStorage == GeoStoreDoubleBuffer);
+ return _otherBuffer;
+ }
+ void switchToOtherBuffer(size_t size) {
+ MATHIC_ASSERT(Configuration::bucketStorage == GeoStoreDoubleBuffer);
+ std::swap(_begin, _otherBuffer);
+ _size = size;
+ if (size > 0)
+ _back = *(end() - 1);
+ }
+ void clear() {
+ _size = 0;
+ }
+ template<class It>
+ void assign(It begin, It end, size_t size) {
+ MATHIC_ASSERT(static_cast<size_t>(end - begin) == size);
+ std::copy(begin, end, _begin);
+ _size = size;
+ if (size > 0)
+ _back = *(end - 1);
+ }
+ template<class It1, class It2>
+ void merge(Geobucket<Configuration>& gb, It1 begin1, It1 end1, It2 begin2, It2 end2) {
+ Entry* end = gb.merge(begin1, end1, begin2, end2, _begin);
+ _size = end - _begin;
+ if (_size > 0)
+ _back = *(end - 1);
+ }
+ void push_back(const Entry& e) {
+ MATHIC_ASSERT(size() < capacity());
+ *(_begin + _size) = e;
+ ++_size;
+ if (Configuration::collectMax)
+ _back = e;
+ }
+ Bucket** getFrontToken() {return _frontPos;}
+ const Bucket** getFrontToken() const {return _frontPos;}
+ void setFrontToken(Bucket** token) {_frontPos = token;}
+
+ Bucket** _frontPos;
+
+ private:
+ Entry* _otherBuffer;
+ Entry _back;
+ Entry* _begin;
+ size_t _size;
+ size_t _capacity;
+ };
+ void addBucket();
+
+ template<bool value> struct Premerge {};
+ template<class It>
+ void insert(Bucket* bucket, It begin, It end, size_t size, Premerge<true>);
+ template<class It>
+ void insert(Bucket* bucket, It begin, It end, size_t size, Premerge<false>);
+
+ template<class It1, class It2, class ResIt>
+ ResIt merge(It1 begin1, It1 end1, It2 begin2, It2 end2, ResIt res);
+ template<class It>
+ size_t singleInsert(It begin, size_t size, const Entry& value) const;
+
+ void moveToEmpty(Bucket& to, Bucket& from);
+ template<class It>
+ void mergeToEmpty(Bucket& to, Bucket& from, It begin, It end);
+ void mergeToNonEmpty(Bucket& into, Bucket& from);
+ template<class It>
+ void mergeToNonEmpty(Bucket& into, It begin, It end);
+
+ size_t _geoBase;
+ std::vector<Bucket> _buckets;
+ Bucket* _bucketBegin;
+ Bucket* _bucketEnd;
+ std::vector<Entry> _mem;
+ Entry* _tmp; // has capacity equal to the largest bucket
+ size_t _entryCount;
+
+ // Has capacity equal to the largest bucket. Only used when
+ // C::premerge is false.
+ Entry* _tmpForNoPremerge;
+ Configuration _conf;
+ GeoFront<Configuration> _front;
+
+#ifdef MATHIC_DEBUG
+ bool isValid() const;
+#endif
+ };
+
+ template<class C>
+ Geobucket<C>::Geobucket(const C& configuration):
+ _bucketBegin(0),
+ _bucketEnd(0),
+ _tmp(0),
+ _entryCount(0),
+ _tmpForNoPremerge(0),
+ _conf(configuration),
+ _front(_conf, _entryCount) {
+ MATHIC_ASSERT(_conf.geoBase > 1);
+ addBucket(); // this avoids the special case of no buckets.
+ ASSERT(_front.debugIsValid(_bucketBegin, _bucketEnd));
+ }
+
+ template<class C>
+ std::string Geobucket<C>::getName() const {
+ std::ostringstream out;
+ out << "Geobucket("
+ << 'b' << _conf.geoBase
+ << 'm' << _conf.minBucketSize
+ << 'i' << C::insertFactor
+ << (C::minBucketBinarySearch ? " mbin" : "")
+ << (C::trackFront ? " tf" : "")
+ << (C::supportDeduplication ? " dedup" : "")
+ << (C::premerge ? " prem" : "")
+ << (C::collectMax ? " col" : "")
+ << (C::bucketStorage == GeoStoreDoubleBuffer ? " db" : "")
+ << (C::bucketStorage == GeoStoreSameSizeBuffer ? " ss" : "")
+ << ')';
+ return out.str();
+ }
+
+ template<class C>
+ void Geobucket<C>::push(Entry entry) {
+ ++_entryCount;
+ Bucket& bucket = *_bucketBegin;
+ if (bucket.size() == bucket.capacity()) {
+ const Entry* p = &entry;
+ insert(_bucketBegin, p, p + 1, 1, Premerge<C::premerge>());
+ return;
+ }
+ if (bucket.empty()) {
+ bucket.push_back(entry);
+ _front.insert(&bucket);
+ } else if (C::minBucketBinarySearch) {
+ size_t range = bucket.size();
+ Entry* begin = bucket.begin();
+ while (true) {
+ // invariant: the position is in the range [begin, begin + range].
+ if (range == 0) {
+ if (begin == bucket.end()) {
+ bucket.push_back(entry);
+ _front.keyIncreased(&bucket);
+ } else
+ bucket.insertAtNotEnd(begin, entry);
+ break;
+ }
+ Entry* mid = begin + range / 2;
+ typename C::CompareResult cmp = _conf.compare(entry, *mid);
+ if (_conf.cmpLessThan(cmp))
+ range /= 2;
+ else if (!C::supportDeduplication || !_conf.cmpEqual(cmp)) {
+ begin = mid;
+ ++begin;
+ range -= range / 2 + 1;
+ } else {
+ --_entryCount;
+ bucket.setEntry(mid, _conf.deduplicate(*mid, entry));
+ break;
+ }
+ }
+ } else {
+ Entry* end = bucket.end();
+ for (Entry* pos = bucket.begin(); pos != end; ++pos) {
+ typename C::CompareResult cmp = _conf.compare(entry, *pos);
+ if (_conf.cmpLessThan(cmp)) {
+ bucket.insertAtNotEnd(pos, entry);
+ return;
+ }
+ if (C::supportDeduplication && _conf.cmpEqual(cmp)) {
+ bucket.setEntry(pos, _conf.deduplicate(*pos, entry));
+ --_entryCount;
+ return;
+ }
+ }
+ bucket.push_back(entry);
+ _front.keyIncreased(&bucket);
+ }
+ }
+
+ template<class C>
+ template<class It>
+ void Geobucket<C>::push(It begin, It end) {
+#ifdef MATHIC_DEBUG
+ if (begin != end) {
+ for (It it = begin; it + 1 != end; ++it) {
+ // deduplication assumes that [begin, end) does not contain
+ // duplicates for efficiency, so support for deduplication implies
+ // that no element can be duplicated within a pushed range.
+ if (C::supportDeduplication) {
+ MATHIC_ASSERT(_conf.cmpLessThan(_conf.compare(*(it + 1), *it)));
+ } else {
+ MATHIC_ASSERT(!_conf.cmpLessThan(_conf.compare(*it, *(it + 1))));
+ }
+ }
+ }
+#endif
+ const size_t entryCount = end - begin;
+ const size_t adjCount = entryCount * C::insertFactor;
+ _entryCount += entryCount;
+ while (adjCount > (_bucketEnd - 1)->capacity())
+ addBucket();
+ for (Bucket* bucket = _bucketBegin; ; ++bucket) {
+ MATHIC_ASSERT(bucket != _bucketEnd);
+ if (adjCount <= bucket->capacity()) {
+ std::reverse_iterator<It> rBegin(end);
+ std::reverse_iterator<It> rEnd(begin);
+ insert(bucket, rBegin, rEnd, entryCount, Premerge<C::premerge>());
+ break;
+ }
+ }
+ MATHIC_ASSERT(isValid());
+ }
+
+ template<class C>
+ void Geobucket<C>::clear() {
+ _entryCount = 0;
+ _front.clear();
+ for (Bucket* bucket = _bucketBegin; bucket != _bucketEnd; ++bucket)
+ bucket->clear();
+ MATHIC_ASSERT(isValid());
+ }
+
+ template<class C>
+ typename Geobucket<C>::Entry Geobucket<C>::pop() {
+ Bucket* maxBucket =
+ const_cast<Bucket*>(_front.getMax(_bucketBegin, _bucketEnd));
+ Entry top = maxBucket->back();
+ maxBucket->pop_back();
+ --_entryCount;
+ _front.keyDecreased(maxBucket);
+ MATHIC_ASSERT(isValid());
+ return top;
+ }
+
+ template<class C>
+ typename Geobucket<C>::Entry Geobucket<C>::top() const {
+ MATHIC_ASSERT(!empty());
+ return _front.getMax(_bucketBegin, _bucketEnd)->back();
+ }
+
+ template<class C>
+ bool Geobucket<C>::empty() const {
+#ifdef MATHIC_DEBUG
+ bool empty = true;
+ for (size_t b = 0; b < _buckets.size(); ++b) {
+ if (!_buckets[b].empty()) {
+ empty = false;
+ break;
+ }
+ }
+ MATHIC_ASSERT(empty == !_entryCount);
+#endif
+ return _entryCount == 0;
+ }
+
+ template<class C>
+ void Geobucket<C>::print(std::ostream& out) const {
+ out << getName() << ": {\n";
+ for (const Bucket* bucket = _bucketBegin; bucket != _bucketEnd; ++bucket) {
+ out << ' ' << (bucket - _bucketBegin) << ":";
+ if (bucket->size() > 4) {
+ out << ' ' << (*bucket)[0] << ' ' << (*bucket)[1] << " ... "
+ << (*bucket)[bucket->size() - 2] << ' '
+ << (*bucket)[bucket->size() - 1];
+ } else
+ for (size_t i = 0; i < bucket->size(); ++i)
+ out << ' ' << (*bucket)[i];
+ out << " [" << bucket->size() << '/' << bucket->capacity() << "]\n";
+ }
+ out << "}\n";
+ }
+
+ template<class C>
+ void Geobucket<C>::addBucket() {
+ // calculate required amount of memory
+ const size_t newBucketSize = _bucketBegin == _bucketEnd ?
+ _conf.minBucketSize : (_bucketEnd - 1)->capacity() * _conf.geoBase;
+ size_t required = 0;
+ typedef typename std::vector<Bucket>::iterator It;
+ for (Bucket* it = _bucketBegin; it != _bucketEnd; ++it) {
+ required += C::bucketStorage == GeoStoreSameSizeBuffer ?
+ newBucketSize : it->capacity();
+ if (C::bucketStorage == GeoStoreDoubleBuffer)
+ required += it->capacity(); // for other buffer
+ }
+ required += newBucketSize; // for new bucket
+ if (C::bucketStorage == GeoStoreDoubleBuffer)
+ required += newBucketSize; // for other buffer
+
+ required += newBucketSize; // for _tmp
+ if (!C::premerge)
+ required += newBucketSize; // for _tmpForNoPremerge
+
+ // allocate new memory
+ std::vector<Entry> newMem(required);
+ std::copy(_mem.begin(), _mem.end(), newMem.begin());
+
+ // move to new memory buffer
+ size_t offset = 0;
+ for (Bucket* it = _bucketBegin; it != _bucketEnd; ++it) {
+ it->setBuffer(&(newMem[offset]));
+ offset += C::bucketStorage == GeoStoreSameSizeBuffer ?
+ newBucketSize : it->capacity();
+ if (C::bucketStorage == GeoStoreDoubleBuffer) {
+ it->setOtherBuffer(&(newMem[offset]));
+ offset += it->capacity();
+ }
+ }
+ Entry* buffer = &(newMem[offset]);
+ offset += newBucketSize;
+ Entry* otherBuffer = 0;
+ if (C::bucketStorage == GeoStoreDoubleBuffer) {
+ otherBuffer = &(newMem[offset]);
+ offset += newBucketSize;
+ }
+ // redirect pointers in _front to point to new memory for _buckets
+ Bucket* oldBucketBegin = _bucketBegin;
+ _buckets.push_back(Bucket(newBucketSize, buffer, otherBuffer));
+ _bucketBegin = &_buckets.front();
+ _bucketEnd = _bucketBegin + _buckets.size();
+ _front.bucketsInvalidated(oldBucketBegin, _bucketBegin);
+ _front.reserveCapacity(_bucketEnd - _bucketBegin);
+
+ _tmp = &(newMem[offset]);
+ offset += newBucketSize;
+ if (!C::premerge) {
+ _tmpForNoPremerge = &(newMem[offset]);
+ offset += newBucketSize;
+ }
+
+ MATHIC_ASSERT(offset == required);
+ _mem.swap(newMem);
+ }
+
+ template<class C>
+ void Geobucket<C>::mergeToNonEmpty(Bucket& to, Bucket& from) {
+ MATHIC_ASSERT(!to.empty());
+ MATHIC_ASSERT(!from.empty());
+ MATHIC_ASSERT(&to != &from);
+ MATHIC_ASSERT(to.size() + from.size() <= to.capacity());
+ if (C::trackFront && _front.larger(&from, &to))
+ _front.swapKeys(&to, &from);
+ mergeToNonEmpty(to, from.begin(), from.end());
+ from.clear();
+ _front.remove(&from);
+ }
+
+ template<class C>
+ template<class It>
+ void Geobucket<C>::mergeToNonEmpty(Bucket& into, It begin, It end) {
+ // todo: template select instead of if
+ // todo: into => to
+ MATHIC_ASSERT(!into.empty());
+ MATHIC_ASSERT(begin != end);
+ MATHIC_ASSERT(static_cast<size_t>(end - begin) <= into.capacity());
+ if (C::bucketStorage == GeoStoreDoubleBuffer) {
+ Entry* other = into.getOtherBuffer();
+ Entry* otherEnd = merge(into.begin(), into.end(), begin, end, other);
+ into.switchToOtherBuffer(otherEnd - other);
+ } else if (C::bucketStorage == GeoStoreSameSizeBuffer) {
+ Entry* tmpEnd = merge(into.begin(), into.end(), begin, end, _tmp);
+ Entry* previousBufferOfInto = into.begin();
+ into.setBufferWithNewEntries(_tmp, tmpEnd - _tmp);
+ _tmp = previousBufferOfInto;
+ } else {
+ Entry* tmpEnd = std::copy(into.begin(), into.end(), _tmp);
+ into.merge(*this, begin, end, _tmp, tmpEnd);
+ }
+ _front.keyIncreased(&into);
+ }
+
+ template<class C>
+ template<class It>
+ void Geobucket<C>::mergeToEmpty(Bucket& to, Bucket& from, It begin, It end) {
+ MATHIC_ASSERT(to.empty());
+ MATHIC_ASSERT(!from.empty()); // so has place in front
+ MATHIC_ASSERT(&to != &from);
+ MATHIC_ASSERT(begin != end);
+ MATHIC_ASSERT(static_cast<size_t>(end - begin) + from.size() <= to.capacity());
+ to.merge(*this, begin, end, from.begin(), from.end());
+ from.clear();
+ _front.swapKeys(&from, &to);
+ _front.keyIncreased(&to);
+ }
+
+ template<class C>
+ void Geobucket<C>::moveToEmpty(Bucket& to, Bucket& from) {
+ MATHIC_ASSERT(&to != &from);
+ MATHIC_ASSERT(to.empty());
+ MATHIC_ASSERT(!from.empty());
+ MATHIC_ASSERT(from.size() <= to.capacity());
+
+ if (C::bucketStorage == GeoStoreSameSizeBuffer) {
+ Entry* previousBufferOfTo = to.begin();
+ to.setBufferWithNewEntries(from.begin(), from.size());
+ from.setBufferWithNewEntries(previousBufferOfTo, 0);
+ } else {
+ to.assign(from.begin(), from.end(), from.size());
+ from.clear();
+ }
+ _front.swapKeys(&from, &to);
+ }
+
+ template<class C>
+ template<class It>
+ void Geobucket<C>::insert
+ (Bucket* p, It begin, It end, size_t incomingSize, Premerge<false>) {
+ MATHIC_ASSERT(!C::premerge);
+ MATHIC_ASSERT(incomingSize == static_cast<size_t>(end - begin));
+ MATHIC_ASSERT(0 < incomingSize);
+ MATHIC_ASSERT(begin != end);
+
+ size_t b = p - _bucketBegin;
+ Bucket& bucket = _buckets[b];
+
+ if (bucket.empty()) {
+ bucket.assign(begin, end, incomingSize);
+ _front.insert(&bucket);
+ return;
+ }
+ if (bucket.size() + incomingSize <= bucket.capacity()) {
+ mergeToNonEmpty(bucket, begin, end);
+ return;
+ }
+
+ size_t accumulatedSize = bucket.size() + incomingSize;
+ for (size_t i = b + 1; ; ++i) {
+ if (i == _buckets.size())
+ addBucket(); // can invalidate bucket reference variable
+ accumulatedSize += _buckets[i].size();
+ if (accumulatedSize <= _buckets[i].capacity())
+ break;
+ }
+
+ // deal with first step separately as the iterator can have
+ // different type (grrrrr)
+ Bucket& current = _buckets[b];
+ MATHIC_ASSERT(b + 1 < _buckets.size());
+ Bucket& next = _buckets[b + 1];
+ if (next.empty()) {
+ mergeToEmpty(next, current, begin, end);
+ return;
+ }
+ Entry* tmpForNoPremergeEnd = merge(
+ begin, end, current.begin(), current.end(), _tmpForNoPremerge);
+ current.clear();
+ _front.remove(¤t);
+ ++b;
+
+ while (true) {
+ Bucket& current = _buckets[b];
+ const size_t predictedSize =
+ (tmpForNoPremergeEnd - _tmpForNoPremerge) + current.size();
+ if (predictedSize <= current.capacity()) {
+ mergeToNonEmpty(current, _tmpForNoPremerge, tmpForNoPremergeEnd);
+ return;
+ }
+ MATHIC_ASSERT(b + 1 < _buckets.size());
+ Bucket& next = _buckets[b + 1];
+ if (next.empty()) {
+ mergeToEmpty(next, current, _tmpForNoPremerge, tmpForNoPremergeEnd);
+ return;
+ }
+ tmpForNoPremergeEnd = merge(_tmpForNoPremerge, tmpForNoPremergeEnd,
+ current.begin(), current.end(), _tmp);
+ std::swap(_tmp, _tmpForNoPremerge);
+ current.clear();
+ _front.remove(¤t);
+ ++b;
+ }
+ }
+
+ template<class C>
+ template<class It>
+ void Geobucket<C>::insert
+ (Bucket* bucket, It begin, It end, size_t size, Premerge<true>) {
+ MATHIC_ASSERT(C::premerge);
+ // ** determine premerge range (bucket, rbegin]
+ Bucket* rbegin = bucket;
+ size_t incomingSize = size;
+ while (true) {
+ if (rbegin->size() + incomingSize <= rbegin->capacity())
+ break;
+ incomingSize = rbegin->size(); // this will be incoming for next bucket
+ ++rbegin;
+ if (rbegin == _bucketEnd) {
+ Bucket* oldBucketBegin = _bucketBegin;
+ addBucket();
+ bucket = (bucket - oldBucketBegin) + _bucketBegin;
+ rbegin = (rbegin - oldBucketBegin) + _bucketBegin;
+ break;
+ }
+ }
+ // ** perform premerges
+ if (bucket != rbegin) {
+ if (!rbegin->empty()) {
+ mergeToNonEmpty(*rbegin, *(rbegin - 1));
+ --rbegin;
+ }
+ for (Bucket* rit = rbegin; rit != bucket; --rit)
+ moveToEmpty(*rit, *(rit - 1));
+ }
+ // ** perform insertion
+ if (bucket->empty()) {
+ bucket->assign(begin, end, size);
+ _front.insert(bucket);
+ } else
+ mergeToNonEmpty(*bucket, begin, end);
+ }
+
+ template<class C>
+ template<class It1, class It2, class ResIt>
+ ResIt Geobucket<C>::merge
+ (It1 begin1, It1 end1, It2 begin2, It2 end2, ResIt res) {
+ if (begin1 == end1) goto range1Done;
+ if (begin2 == end2) goto range2Done;
+ while (true) {
+ typename C::CompareResult cmp = _conf.compare(*begin1, *begin2);
+ if (_conf.cmpLessThan(cmp)) {
+ *res = *begin1;
+ ++res;
+ ++begin1;
+ if (begin1 == end1) goto range1Done;
+ } else if (!C::supportDeduplication || !_conf.cmpEqual(cmp)) {
+ *res = *begin2;
+ ++res;
+ ++begin2;
+ if (begin2 == end2) goto range2Done;
+ } else {
+ *res = _conf.deduplicate(*begin1, *begin2);
+ ++res;
+ ++begin1;
+ ++begin2;
+ --_entryCount;
+ if (begin1 == end1) goto range1Done;
+ if (begin2 == end2) goto range2Done;
+ }
+ }
+ range1Done: return std::copy(begin2, end2, res);
+ range2Done: return std::copy(begin1, end1, res);
+ }
+
+ template<class C>
+ Geobucket<C>::Bucket::Bucket
+ (size_t capacity, Entry* buffer, Entry* otherBuffer):
+ _frontPos(0),
+ _otherBuffer(otherBuffer),
+ _begin(buffer),
+ _size(0),
+ _capacity(capacity) {
+ MATHIC_ASSERT(C::bucketStorage == GeoStoreDoubleBuffer ?
+ otherBuffer != 0 : otherBuffer == 0);
+ }
+
+ template<class C>
+ size_t Geobucket<C>::getMemoryUse() const {
+ return _mem.capacity() * sizeof(_mem.front()) +
+ _buckets.capacity() * sizeof(_buckets.front()) +
+ _front.getMemoryUse();
+ }
+
+#ifdef MATHIC_DEBUG
+ template<class C>
+ bool Geobucket<C>::isValid() const {
+ MATHIC_ASSERT(_conf.geoBase >= 2);
+ MATHIC_ASSERT(!_buckets.empty());
+ MATHIC_ASSERT(_bucketBegin == &_buckets.front());
+ MATHIC_ASSERT(_bucketEnd == _bucketBegin + _buckets.size());
+ MATHIC_ASSERT(_buckets.front().capacity() >= 1);
+
+ size_t entryCount = 0;
+ for (size_t b = 0; b < _buckets.size(); ++b) {
+ const Bucket& bucket = _buckets[b];
+ entryCount += bucket.size();
+ if (bucket.empty())
+ continue;
+ for (const Entry* it = bucket.begin(); it != bucket.end() - 1; ++it) {
+ MATHIC_ASSERT(!_conf.cmpLessThan(_conf.compare(*(it + 1), *it)));
+ }
+ }
+ MATHIC_ASSERT(entryCount == _entryCount);
+ return _front.debugIsValid(_bucketBegin, _bucketEnd);
+ }
+#endif
+}
+
+#endif
diff --git a/src/mathic/Heap.h b/src/mathic/Heap.h
new file mode 100755
index 0000000..a3f7978
--- /dev/null
+++ b/src/mathic/Heap.h
@@ -0,0 +1,200 @@
+#ifndef MATHIC_HEAP_GUARD
+#define MATHIC_HEAP_GUARD
+
+#include "stdinc.h"
+#include "ComTree.h"
+#include <vector>
+#include <ostream>
+#include <string>
+
+namespace mathic {
+ /** A heap priority queue.
+
+ Configuration serves the same role as for Geobucket. It must have these
+ fields that work as for Geobucket.
+
+ * A type Entry
+ * A type CompareResult
+ * A const or static method: CompareResult compare(Entry, Entry)
+ * A const or static method: bool cmpLessThan(CompareResult)
+ * A static const bool supportDeduplication
+ * A static or const method: bool cmpEqual(CompareResult)
+
+ It also has these additional fields:
+
+ * A static const bool fastIndex
+ If this field is true, then a faster way of calculating indexes is used.
+ This requires sizeof(Entry) to be a power of two! This can be achieved
+ by adding padding to Entry, but this class does not do that for you.
+ */
+ template<class C>
+ class Heap {
+ public:
+ typedef C Configuration;
+ typedef typename Configuration::Entry Entry;
+
+ Heap(const Configuration& configuration): _conf(configuration) {}
+ Configuration& getConfiguration() {return _conf;}
+ const Configuration& getConfiguration() const {return _conf;}
+
+ template<class T>
+ void forAll(T& t) const {
+ Node stop = _tree.lastLeaf().next();
+ for (Node it = Node(); it != stop; ++it)
+ if (!t.proceed(_tree[it]))
+ return;
+ }
+
+ std::string getName() const;
+ void push(Entry entry);
+ template<class It>
+ void push(It begin, It end);
+ void clear();
+ Entry pop();
+ Entry top() const {return _tree[Node()];}
+ bool empty() const {return _tree.empty();}
+ size_t size() const {return _tree.size();}
+
+ void print(std::ostream& out) const;
+
+ void decreaseTop(Entry newEntry);
+
+ size_t getMemoryUse() const;
+
+ private:
+ typedef ComTree<Entry, Configuration::fastIndex> Tree;
+ typedef typename Tree::Node Node;
+
+ Node moveHoleDown(Node hole);
+ void moveValueUp(Node pos, Entry value);
+
+#ifdef MATHIC_DEBUG
+ bool isValid() const;
+#endif
+
+ Tree _tree;
+ Configuration _conf;
+ };
+
+ template<class C>
+ size_t Heap<C>::getMemoryUse() const {
+ return _tree.getMemoryUse();
+ }
+
+ template<class C>
+ std::string Heap<C>::getName() const {
+ return std::string("heap(") +
+ (C::fastIndex ? "fi" : "si") +
+ (C::supportDeduplication ? " dedup" : "") +
+ ')';
+ }
+
+ template<class C>
+ void Heap<C>::push(Entry entry) {
+ _tree.pushBack(entry);
+ moveValueUp(_tree.lastLeaf(), entry);
+ MATHIC_ASSERT(isValid());
+ }
+
+ template<class C>
+ template<class It>
+ void Heap<C>::push(It begin, It end) {
+ for (; begin != end; ++begin)
+ push(*begin);
+ }
+
+ template<class C>
+ void Heap<C>::decreaseTop(Entry newEntry) {
+ moveValueUp(moveHoleDown(Node()), newEntry);
+ MATHIC_ASSERT(isValid());
+ }
+
+ template<class C>
+ void Heap<C>::clear() {
+ _tree.clear();
+ MATHIC_ASSERT(isValid());
+ }
+
+ template<class C>
+ typename Heap<C>::Entry Heap<C>::pop() {
+ Entry top = _tree[Node()];
+ Entry movedValue = _tree[_tree.lastLeaf()];
+ _tree.popBack();
+ if (!_tree.empty())
+ moveValueUp(moveHoleDown(Node()), movedValue);
+ return top;
+ MATHIC_ASSERT(isValid());
+ }
+
+ template<class C>
+ void Heap<C>::print(std::ostream& out) const {
+ out << getName() << ": {" << _tree << "}\n";
+ }
+
+ template<class C>
+ typename Heap<C>::Node Heap<C>::moveHoleDown(Node hole) {
+ const Node firstWithout2Children = _tree.lastLeaf().next().parent();
+ while (hole < firstWithout2Children) {
+ // can assume hole has two children here
+ Node child = hole.left();
+ Node sibling = child.next();
+ if (_conf.cmpLessThan(_conf.compare(_tree[child], _tree[sibling])))
+ child = sibling;
+ _tree[hole] = _tree[child];
+ hole = child;
+ }
+ // if we are at a node that has a single left child
+ if (hole == firstWithout2Children && _tree.lastLeaf().isLeft()) {
+ Node child = hole.left();
+ _tree[hole] = _tree[child];
+ hole = child;
+ }
+ return hole;
+ }
+
+ template<class C>
+ void Heap<C>::moveValueUp(Node pos, Entry value) {
+ const Node origPos = pos;
+ again:
+ while (!pos.isRoot()) {
+ const Node up = pos.parent();
+ typename C::CompareResult cmp = _conf.compare(_tree[up], value);
+ if (_conf.cmpLessThan(cmp)) {
+ _tree[pos] = _tree[up];
+ pos = up;
+ } else if (C::supportDeduplication && _conf.cmpEqual(cmp)) {
+ _tree[up] = _conf.deduplicate(_tree[up], value);
+ if (pos != origPos) {
+ // move elements back
+ Entry tmp = _tree[origPos];
+ for (Node p = origPos.parent(); p != pos; p = p.parent())
+ std::swap(tmp, _tree[p]);
+ }
+ pos = origPos;
+ value = _tree[_tree.lastLeaf()];
+ _tree.popBack();
+ if (origPos == _tree.lastLeaf().next()) {
+ MATHIC_ASSERT(isValid());
+ return;
+ }
+ goto again;
+ } else
+ break;
+ }
+ _tree[pos] = value;
+ MATHIC_ASSERT(isValid());
+ }
+
+#ifdef MATHIC_DEBUG
+ template<class C>
+ bool Heap<C>::isValid() const {
+ MATHIC_ASSERT(_tree.isValid());
+ for (Node i = Node().next(); i <= _tree.lastLeaf(); ++i) {
+ MATHIC_ASSERT(!_conf.cmpLessThan(_conf.compare(_tree[i.parent()], _tree[i])));
+ }
+ return true;
+ }
+#endif
+}
+
+#endif
diff --git a/src/mathic/HelpAction.cpp b/src/mathic/HelpAction.cpp
new file mode 100755
index 0000000..32c7b9d
--- /dev/null
+++ b/src/mathic/HelpAction.cpp
@@ -0,0 +1,113 @@
+#include "HelpAction.h"
+
+#include "CliParameter.h"
+#include "error.h"
+#include "display.h"
+#include "ColumnPrinter.h"
+#include "CliParser.h"
+
+#include <iostream>
+#include <algorithm>
+
+namespace mathic {
+ HelpAction::HelpAction() {}
+
+ const char* HelpAction::name() const {
+ return staticName();
+ }
+
+ const char* HelpAction::description() const {
+ return
+ "Typing `frobby help' displays a list of the available actions.\n"
+ "Typing `frobby help ACTION' displays a detailed description of that "
+ "action.\n\n"
+ "As an example, typing `frobby help irrdecom' will yield detailed "
+ "information about the irrdecom action.";
+ }
+
+ const char* HelpAction::shortDescription() const {
+ return "Return information about the command line interface.";
+ }
+
+
+ void HelpAction::directOptions(
+ std::vector<std::string> tokens,
+ CliParser& parser
+ ) {
+ _parser = &parser;
+ if (tokens.size() == 1)
+ _topic = tokens.front();
+ else if (tokens.size() > 1)
+ reportError("Did not expect second option \"" + tokens[1] + "\".");
+ }
+
+ void HelpAction::pushBackParameters(std::vector<CliParameter*>& parameters) {
+ }
+
+ namespace {
+ // Helper function for displayActionHelp().
+ bool paramCmp(CliParameter* a, CliParameter* b) {
+ MATHIC_ASSERT(a != 0);
+ MATHIC_ASSERT(b != 0);
+ return std::string(a->name()) < b->name();
+ }
+ }
+
+ void HelpAction::displayActionHelp(Action& action) {
+ std::ostringstream out;
+ out << "Displaying information on action: " << action.name() << "\n\n";
+ out << action.description() << "\n";
+
+ std::vector<CliParameter*> parameters;
+ action.pushBackParameters(parameters);
+ sort(parameters.begin(), parameters.end(), paramCmp);
+
+ display(out.str());
+
+ if (!parameters.empty()) {
+ fprintf(stderr, "\nThe parameters accepted by %s are as follows.\n",
+ action.name());
+
+ typedef std::vector<CliParameter*>::const_iterator cit;
+ for (cit it = parameters.begin(); it != parameters.end(); ++it) {
+ std::string defaultValue = (*it)->valueAsString();
+ fprintf(stderr, "\n -%s %s (default is %s)\n",
+ (*it)->name().c_str(),
+ (*it)->argumentType().c_str(),
+ (*it)->valueAsString().c_str());
+ display((*it)->description(), " ");
+ }
+ }
+ }
+
+ void HelpAction::performAction() {
+ if (_topic != "") {
+ displayActionHelp(*_parser->createActionWithPrefix(_topic));
+ return;
+ }
+
+ std::ostringstream out;
+
+ out << _parser->helpPreMessage() << '\n';
+
+ ColumnPrinter printer;
+ printer.addColumn(false, " ");
+ printer.addColumn(true, " - ");
+
+ std::vector<std::string> names;
+ _parser->pushBackRegisteredActionNames(names);
+ for (std::vector<std::string>::const_iterator it = names.begin();
+ it != names.end(); ++it) {
+ std::auto_ptr<Action> action(_parser->createActionWithPrefix(*it));
+ printer[0] << action->name() << '\n';
+ printer[1] << action->shortDescription() << '\n';
+ }
+ printer.print(out);
+ out << '\n' << _parser->helpPostMessage() << '\n';
+ display(out.str());
+ }
+
+ const char* HelpAction::staticName() {
+ return "help";
+ }
+}
diff --git a/src/mathic/HelpAction.h b/src/mathic/HelpAction.h
new file mode 100755
index 0000000..e724afd
--- /dev/null
+++ b/src/mathic/HelpAction.h
@@ -0,0 +1,34 @@
+#ifndef MATHIC_HELP_ACTION_GUARD
+#define MATHIC_HELP_ACTION_GUARD
+
+#include "stdinc.h"
+#include "Action.h"
+#include <string>
+
+namespace mathic {
+ class HelpAction : public Action {
+ public:
+ HelpAction();
+
+ virtual void directOptions
+ (std::vector<std::string> tokens, CliParser& parser);
+ virtual void performAction();
+
+ virtual const char* name() const;
+ virtual const char* description() const;
+ virtual const char* shortDescription() const;
+ virtual void pushBackParameters(std::vector<CliParameter*>& parameters);
+
+ virtual bool isHelpAction() const {return true;}
+
+ static const char* staticName();
+
+ private:
+ void displayActionHelp(Action& action);
+
+ CliParser* _parser;
+ std::string _topic;
+ };
+}
+
+#endif
diff --git a/src/mathic/IntegerParameter.cpp b/src/mathic/IntegerParameter.cpp
new file mode 100755
index 0000000..f17cf32
--- /dev/null
+++ b/src/mathic/IntegerParameter.cpp
@@ -0,0 +1,36 @@
+#include "IntegerParameter.h"
+
+#include "error.h"
+#include <sstream>
+#include <cctype>
+
+namespace mathic {
+ IntegerParameter::IntegerParameter(const std::string& name,
+ const std::string& description,
+ unsigned int defaultValue):
+ CliParameter(name, description),
+ _value(defaultValue) {
+ }
+
+ std::string IntegerParameter::argumentType() const {
+ return "INTEGER";
+ }
+
+ std::string IntegerParameter::valueAsString() const {
+ std::ostringstream out;
+ out << value();
+ return out.str();
+ }
+
+ void IntegerParameter::processArgument(const std::string& argument) {
+ std::istringstream in(argument);
+ in >> _value;
+ std::ostringstream out;
+ out << _value;
+ if (out.str() != argument) {
+ reportError("The value given to option -" + name() + " was not "
+ "as expected. It must be a non-negative integer in the range "
+ "[0, 2^31-1].");
+ }
+ }
+}
diff --git a/src/mathic/IntegerParameter.h b/src/mathic/IntegerParameter.h
new file mode 100755
index 0000000..e16f096
--- /dev/null
+++ b/src/mathic/IntegerParameter.h
@@ -0,0 +1,31 @@
+#ifndef MATHIC_INTEGER_PARAMETER_GUARD
+#define MATHIC_INTEGER_PARAMETER_GUARD
+
+#include "stdinc.h"
+#include "CliParameter.h"
+#include <utility>
+#include <string>
+
+namespace mathic {
+ class IntegerParameter : public CliParameter {
+ public:
+ IntegerParameter(const std::string& name,
+ const std::string& description,
+ unsigned int defaultValue);
+
+ unsigned int value() const {return _value;}
+ void setValue(unsigned int value) {_value = value;}
+
+ operator unsigned int() const {return value();}
+ void operator=(unsigned int value) {setValue(value);}
+
+ virtual std::string argumentType() const;
+ virtual std::string valueAsString() const;
+ virtual void processArgument(const std::string& argument);
+
+ private:
+ unsigned int _value;
+ };
+}
+
+#endif
diff --git a/src/mathic/KDEntryArray.h b/src/mathic/KDEntryArray.h
new file mode 100755
index 0000000..92e3eea
--- /dev/null
+++ b/src/mathic/KDEntryArray.h
@@ -0,0 +1,493 @@
+#ifndef MATHIC_K_D_ENTRY_ARRAY_GUARD
+#define MATHIC_K_D_ENTRY_ARRAY_GUARD
+
+#include "stdinc.h"
+
+#include "DivMask.h"
+#include "Comparer.h"
+
+#include <stdexcept>
+#include <memtailor.h>
+
+namespace mathic {
+ template<class C, class EE>
+ class KDEntryArray : public DivMask::HasDivMask<C::UseTreeDivMask> {
+ public:
+ typedef typename C::Entry Entry;
+ typedef typename C::Exponent Exponent;
+ typedef EE ExtEntry;
+ typedef EE* iterator;
+ typedef const EE* const_iterator;
+ typedef const EE& const_reference;
+ typedef EE value_type;
+ typedef DivMask::Calculator<C> DivMaskCalculator;
+
+ KDEntryArray(memt::Arena& arena, const C& conf);
+
+ template<class Iter>
+ KDEntryArray(Iter begin, Iter end, memt::Arena& arena,
+ const DivMaskCalculator& calc, const C& conf);
+ template<class Iter>
+ KDEntryArray(Iter begin, Iter end, memt::Arena& arena, const C& conf);
+
+ void clear();
+
+ void recalculateTreeDivMask();
+#ifdef DEBUG
+ bool debugIsValid() const;
+#endif
+
+ iterator begin() {return reinterpret_cast<ExtEntry*>(_beginMemory);}
+ const_iterator begin() const {
+ return reinterpret_cast<const ExtEntry*>(_beginMemory);
+ }
+ iterator end() {return _end;}
+ const_iterator end() const {return _end;}
+
+ bool empty() const {return begin() == end();}
+ size_t size() const {return std::distance(begin(), end());}
+ EE& front() {MATHIC_ASSERT(!empty()); return *begin();}
+ const EE& front() const {MATHIC_ASSERT(!empty()); return *begin();}
+ EE& back() {MATHIC_ASSERT(!empty()); return *(_end - 1);}
+ const EE& back() const {MATHIC_ASSERT(!empty()); return *(_end - 1);}
+
+ void push_back(const EE& entry);
+ void pop_back();
+ void insert(iterator it, const EE& entry);
+ void insert(const EE& entry, const C& conf);
+
+ /** Returns how many were removed. */
+ template<class EM, class MO>
+ size_t removeMultiples(const EM& monomial, MO& out, const C& conf);
+
+ template<class M>
+ bool removeElement(const M& monomial, const C& conf);
+
+ template<class EM>
+ inline iterator findDivisor(const EM& extMonomial, const C& conf);
+
+ template<class EM, class DO>
+ inline bool findAllDivisors(const EM& extMonomial, DO& out, const C& conf);
+
+ template<class EM, class Output>
+ inline bool findAllMultiples
+ (const EM& extMonomial, Output& out, const C& conf);
+
+ template<class EO>
+ bool forAll(EO& eo);
+
+ bool allStrictlyGreaterThan(size_t var, Exponent exp, const C& conf);
+ bool allLessThanOrEqualTo(size_t var, Exponent exp, const C& conf);
+
+ /** Reorders [begin, iter) and chooses a var and an exp such that
+ if mid is the returned value, then [begin, mid) has less than or
+ equal to exp exponent of var and [mid,end) has strictly greater
+ exponent. The initial value of var is a hint that var + 1 could
+ be a good place to start the search for a suitable value of var.
+ begin must not equal end.
+
+ If not null, the entry os taken into account when deciding which
+ split to perform. The Entry is NOT inserted into [begin, end). */
+ template<class Iter>
+ static Iter split(
+ Iter begin,
+ Iter end,
+ size_t& var,
+ Exponent& exp,
+ const C& conf,
+ const ExtEntry* extEntry = 0
+ );
+
+ using DivMask::HasDivMask<C::UseTreeDivMask>::resetDivMask;
+ using DivMask::HasDivMask<C::UseTreeDivMask>::getDivMask;
+
+ private:
+ static Entry& getEntry(Entry& e) {return e;}
+ static const Entry& getEntry(const Entry& e) {return e;}
+ static Entry& getEntry(ExtEntry& e) {return e.get();}
+ static const Entry& getEntry(const ExtEntry& e) {return e.get();}
+
+ KDEntryArray(const KDEntryArray&); // unavailable
+ void operator=(const KDEntryArray&); // unavailable
+
+ class SplitEqualOrLess;
+
+
+ /** This is the memory for the entries. It is kept as a raw char*
+ to avoid constructing all the entries right away. */
+ char _beginMemory[C::LeafSize * sizeof(ExtEntry)];
+ iterator _end; // points into _beginMemory
+#ifdef MATHIC_DEBUG
+ const bool _sortOnInsertDebug;
+#endif
+ };
+
+ template<class C, class EE>
+ class KDEntryArray<C, EE>::SplitEqualOrLess {
+ public:
+ typedef typename C::Exponent Exponent;
+ typedef typename C::Entry Entry;
+ SplitEqualOrLess(size_t var, const Exponent& exp, const C& conf):
+ _var(var), _exp(exp), _conf(conf) {}
+ bool operator()(const Entry& entry) const {
+ return !(_exp < _conf.getExponent(entry, _var));
+ }
+ bool operator()(const ExtEntry& entry) const {
+ return !(_exp < _conf.getExponent(entry.get(), _var));
+ }
+ private:
+ size_t _var;
+ const Exponent& _exp;
+ const C& _conf;
+ };
+
+ template<class C, class EE>
+ template<class Iter>
+ Iter KDEntryArray<C, EE>::split(
+ Iter begin,
+ Iter end,
+ size_t& var,
+ Exponent& exp,
+ const C& conf,
+ const ExtEntry* extEntry
+ ) {
+ MATHIC_ASSERT(begin != end);
+ const size_t varCount = conf.getVarCount();
+ for (size_t i = 0; i < varCount; ++i) {
+ var = (var + 1) % conf.getVarCount();
+
+ typename C::Exponent min;
+ typename C::Exponent max;
+ if (extEntry == 0) {
+ min = conf.getExponent(getEntry(*begin), var);
+ max = conf.getExponent(getEntry(*begin), var);
+ } else {
+ min = conf.getExponent(getEntry(*extEntry), var);
+ max = conf.getExponent(getEntry(*extEntry), var);
+ }
+ for (Iter it = begin; it != end; ++it) {
+ min = std::min(min, conf.getExponent(getEntry(*it), var));
+ max = std::max(max, conf.getExponent(getEntry(*it), var));
+ }
+ if (min == max)
+ continue;
+ // this formula for the average avoids overflow
+ exp = min + (max - min) / 2;
+ SplitEqualOrLess cmp(var, exp, conf);
+ return std::partition(begin, end, cmp);
+ }
+ MATHIC_ASSERT(false);
+ throw std::logic_error("ERROR: Inserted duplicate entry into a KD tree.");
+ }
+
+ template<class C, class EE>
+ KDEntryArray<C, EE>::KDEntryArray(memt::Arena& arena, const C& conf)
+#ifdef MATHIC_DEBUG
+ :_sortOnInsertDebug(conf.getSortOnInsert())
+#endif
+ {
+ _end = begin();
+ }
+
+ template<class C, class EE>
+ template<class Iter>
+ KDEntryArray<C, EE>::KDEntryArray(
+ Iter begin,
+ Iter end,
+ memt::Arena& arena,
+ const DivMaskCalculator& calc,
+ const C& conf)
+#ifdef MATHIC_DEBUG
+ :_sortOnInsertDebug(conf.getSortOnInsert())
+#endif
+ {
+ MATHIC_ASSERT(static_cast<size_t>(std::distance(begin, end)) <=
+ C::LeafSize);
+ _end = this->begin();
+ // cannot directly copy as memory is not constructed.
+ for (; begin != end; ++begin)
+ push_back(EE(*begin, calc, conf));
+ if (conf.getSortOnInsert())
+ std::sort(this->begin(), this->end(), Comparer<C>(conf));
+ }
+
+ template<class C, class EE>
+ template<class Iter>
+ KDEntryArray<C, EE>::KDEntryArray(
+ Iter begin,
+ Iter end,
+ memt::Arena& arena,
+ const C& conf)
+#ifdef MATHIC_DEBUG
+ :_sortOnInsertDebug(conf.getSortOnInsert())
+#endif
+ {
+ MATHIC_ASSERT(static_cast<size_t>(std::distance(begin, end)) <=
+ C::LeafSize);
+ _end = this->begin();
+ // cannot directly copy as memory is not constructed.
+ for (; begin != end; ++begin)
+ push_back(*begin);
+ if (conf.getSortOnInsert())
+ std::sort(this->begin(), this->end(), Comparer<C>(conf));
+ }
+
+ template<class C, class EE>
+ void KDEntryArray<C, EE>::push_back(const EE& entry) {
+ MATHIC_ASSERT(size() < C::LeafSize);
+ new (_end) EE(entry);
+ updateToLowerBound(entry);
+ ++_end;
+ }
+
+ template<class C, class EE>
+ void KDEntryArray<C, EE>::pop_back() {
+ MATHIC_ASSERT(!empty());
+ --_end;
+ _end->~EE();
+ }
+
+ template<class C, class EE>
+ void KDEntryArray<C, EE>::insert(iterator it, const EE& entry) {
+ MATHIC_ASSERT(size() < C::LeafSize);
+ if (it == end()) {
+ push_back(entry);
+ return;
+ }
+ push_back(back());
+ iterator moveTo = end();
+ for (--moveTo; moveTo != it; --moveTo)
+ *moveTo = *(moveTo - 1);
+ updateToLowerBound(entry);
+ *it = entry;
+ }
+
+ template<class C, class EE>
+ void KDEntryArray<C, EE>::insert(const EE& entry, const C& conf) {
+ MATHIC_ASSERT(size() < C::LeafSize);
+ if (!conf.getSortOnInsert())
+ push_back(entry);
+ else {
+ iterator it = std::upper_bound(begin(), end(), entry, Comparer<C>(conf));
+ insert(it, entry);
+ }
+ }
+
+ template<class C, class EE>
+ void KDEntryArray<C, EE>::clear() {
+ while (!empty())
+ pop_back();
+ }
+
+ template<class C, class EE>
+ template<class EM, class MO>
+ size_t KDEntryArray<C, EE>::removeMultiples
+ (const EM& monomial, MO& out, const C& conf) {
+ MATHIC_ASSERT(C::AllowRemovals);
+ if (C::LeafSize == 1) { // special case for performance
+ if (empty() || !monomial.divides(*begin(), conf))
+ return 0;
+ out.push_back(begin()->get());
+ pop_back();
+ return 1;
+ }
+
+ iterator it = begin();
+ iterator oldEnd = end();
+ for (; it != oldEnd; ++it) {
+ if (monomial.divides(*it, conf)) {
+ out.push_back(it->get());
+ break;
+ }
+ }
+ if (it == oldEnd)
+ return 0;
+ iterator newEnd = it;
+ for (++it; it != oldEnd; ++it) {
+ if (!monomial.divides(*it, conf)) {
+ *newEnd = *it;
+ ++newEnd;
+ } else
+ out.push_back(it->get());
+ }
+ // cannot just set _end directly as the superfluous
+ // entries at the end need to be destructed.
+ const size_t newSize = std::distance(begin(), newEnd);
+ const size_t removedCount = size() - newSize;
+ MATHIC_ASSERT(newSize < size());
+ do {
+ pop_back();
+ } while (newSize < size());
+ MATHIC_ASSERT(size() == newSize);
+ return removedCount;
+ }
+
+ template<class C, class EE>
+ template<class M>
+ bool KDEntryArray<C, EE>::removeElement(const M& monomial, const C& conf) {
+ const size_t varCount = conf.getVarCount();
+ const_iterator stop = end();
+ for (iterator it = begin(); it != stop; ++it) {
+ for (size_t var = 0; var < varCount; ++var)
+ if (conf.getExponent(monomial, var) != conf.getExponent(it->get(), var))
+ goto skip;
+ if (it != end()) {
+ const_iterator next = it;
+ for (++next; next != end(); ++it, ++next)
+ *it = *next;
+ }
+ pop_back();
+ return true;
+ skip:;
+ }
+ return false;
+ }
+
+ template<class C, class EE>
+ template<class EM>
+ typename KDEntryArray<C, EE>::iterator
+ KDEntryArray<C, EE>::findDivisor(const EM& extMonomial, const C& conf) {
+ if (C::UseTreeDivMask &&
+ C::LeafSize > 1 && // no reason to do it for just 1 leaf
+ !getDivMask().canDivide(extMonomial.getDivMask()))
+ return end();
+
+ if (C::LeafSize == 1) { // special case for performance
+ ASSERT(C::AllowRemovals || !empty());
+ if ((!C::AllowRemovals || !empty()) &&
+ begin()->divides(extMonomial, conf))
+ return begin();
+ else
+ return end();
+ }
+ else if (!conf.getSortOnInsert()) {
+ const iterator stop = end();
+ for (iterator it = begin(); it != stop; ++it)
+ if (it->divides(extMonomial, conf))
+ return it;
+ return stop;
+ } else {
+ iterator rangeEnd =
+ std::upper_bound(begin(), end(), extMonomial, Comparer<C>(conf));
+ iterator it = begin();
+ for (; it != rangeEnd; ++it)
+ if (it->divides(extMonomial, conf))
+ return it;
+ return end();
+ }
+ }
+
+ template<class C, class EE>
+ template<class EM, class DO>
+ bool KDEntryArray<C, EE>::
+ findAllDivisors(const EM& extMonomial, DO& out, const C& conf) {
+ if (C::UseTreeDivMask &&
+ C::LeafSize > 1 && // no reason to do it for just 1 leaf
+ !getDivMask().canDivide(extMonomial.getDivMask()))
+ return end();
+
+ if (C::LeafSize == 1) { // special case for performance
+ ASSERT(C::AllowRemovals || !empty());
+ return (C::AllowRemovals && empty()) ||
+ !begin()->divides(extMonomial, conf) ||
+ out.proceed(begin()->get());
+ } else if (!conf.getSortOnInsert()) {
+ const iterator stop = end();
+ for (iterator it = begin(); it != stop; ++it)
+ if (it->divides(extMonomial, conf))
+ if (!out.proceed(it->get()))
+ return false;
+ } else {
+ iterator rangeEnd =
+ std::upper_bound(begin(), end(), extMonomial, Comparer<C>(conf));
+ iterator it = begin();
+ for (; it != rangeEnd; ++it)
+ if (it->divides(extMonomial, conf))
+ if (!out.proceed(it->get()))
+ return false;
+ }
+ return true;
+ }
+
+ template<class C, class EE>
+ template<class EM, class DO>
+ bool KDEntryArray<C, EE>::
+ findAllMultiples(const EM& extMonomial, DO& out, const C& conf) {
+ if (C::LeafSize == 1) { // special case for performance
+ ASSERT(C::AllowRemovals || !empty());
+ return (C::AllowRemovals && empty()) ||
+ !extMonomial.divides(*begin(), conf) ||
+ out.proceed(begin()->get());
+ }
+
+ // todo: consider making sorted version
+ const iterator stop = end();
+ for (iterator it = begin(); it != stop; ++it)
+ if (extMonomial.divides(*it, conf))
+ if (!out.proceed(it->get()))
+ return false;
+ return true;
+ }
+
+ template<class C, class EE>
+ template<class EO>
+ bool KDEntryArray<C, EE>::forAll(EO& output) {
+ if (C::LeafSize == 1) { // special case for performance
+ ASSERT(C::AllowRemovals || !empty());
+ return (C::AllowRemovals && empty()) || output.proceed(begin()->get());
+ }
+ const iterator stop = end();
+ for (iterator it = begin(); it != stop; ++it)
+ if (!output.proceed(it->get()))
+ return false;
+ return true;
+ }
+
+ template<class C, class EE>
+ bool KDEntryArray<C, EE>::allStrictlyGreaterThan(
+ size_t var,
+ Exponent exp,
+ const C& conf
+ ) {
+ for (const_iterator it = begin(); it != end(); ++it)
+ if (!(exp < conf.getExponent(it->get(), var)))
+ return false;
+ return true;
+ }
+
+ template<class C, class EE>
+ bool KDEntryArray<C, EE>::allLessThanOrEqualTo(
+ size_t var,
+ Exponent exp,
+ const C& conf
+ ) {
+ for (const_iterator it = begin(); it != end(); ++it)
+ if (exp < conf.getExponent(it->get(), var))
+ return false;
+ return true;
+ }
+
+ template<class C, class EE>
+ void KDEntryArray<C, EE>::recalculateTreeDivMask() {
+ if (!C::UseTreeDivMask)
+ return;
+ resetDivMask();
+ for (const_iterator it = begin(); it != end(); ++it)
+ updateToLowerBound(*it);
+ }
+#ifdef DEBUG
+ template<class C, class EE>
+ bool KDEntryArray<C, EE>::debugIsValid() const {
+ MATHIC_ASSERT(C::AllowRemovals || !empty());
+ MATHIC_ASSERT(static_cast<size_t>(end() - begin()) <= C::LeafSize);
+ if (C::UseTreeDivMask && C::LeafSize > 1) {
+ for (const_iterator it = begin(); it != end(); ++it) {
+ MATHIC_ASSERT(getDivMask().canDivide(it->getDivMask()));
+ }
+ }
+ return true;
+ }
+#endif
+}
+
+#endif
diff --git a/src/mathic/KDTree.h b/src/mathic/KDTree.h
new file mode 100755
index 0000000..8290bb2
--- /dev/null
+++ b/src/mathic/KDTree.h
@@ -0,0 +1,366 @@
+#ifndef MATHIC_K_D_TREE_GUARD
+#define MATHIC_K_D_TREE_GUARD
+
+#include "stdinc.h"
+#include "DivMask.h"
+#include "BinaryKDTree.h"
+#include "PackedKDTree.h"
+#include <memtailor.h>
+#include <list>
+#include <string>
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+#include <vector>
+
+namespace mathic {
+ /** An object that supports queries for divisors of a monomial using
+ a KD Tree (K Dimensional Tree). See DivFinder.h for more documentation.
+
+ Extra fields for Configuration:
+
+ * bool getSortOnInsert() const
+ Return true to keep the monomials in leaves sorted to speed up queries.
+
+ * size_t getLeafSize() const
+ Return the fixed maximal size of a leaf.
+
+ * static const bool AllowRemovals
+ If false, it is an error to call methods that remove elements from
+ the data structure. This can be a slight speed up in some cases.
+ Clear and rebuild is still allowed even if this field is false.
+ */
+ template<class Configuration>
+ class KDTree;
+
+ namespace KDTreeInternal {
+ // cannot do this inside KDTree as template partial specializations
+ // cannot be done inside a class.
+ template<class C, bool Pack>
+ struct SelectTree {
+ typedef BinaryKDTree<C> Tree;
+ };
+ template<class C>
+ struct SelectTree<C, true> {
+ typedef PackedKDTree<C> Tree;
+ };
+ }
+
+ template<class C>
+ class KDTree {
+ private:
+ // for figuring out which kd tree implementation to use
+ typedef typename KDTreeInternal::SelectTree<C, C::PackedTree>::Tree Tree;
+ typedef typename Tree::ExtEntry ExtEntry;
+ typedef typename Tree::ExtMonoRef ExtMonoRef;
+ public:
+ typedef C Configuration;
+
+ /** Constructs an object with the given configuration. The configuration
+ is copied into the object, so a reference to the passed-in object is
+ not kept. The configuration is not copied other than the initial copy. */
+ KDTree(const C& configuration):
+ _divMaskCalculator(configuration),
+ _tree(configuration),
+ _size(0) {
+ resetNumberOfChangesTillRebuild();
+ if (getConfiguration().getUseDivisorCache())
+ _divisorCache = 0;
+ }
+
+ static const bool UseDivMask = C::UseDivMask;
+ typedef typename C::Monomial Monomial;
+ typedef typename C::Entry Entry;
+ typedef typename C::Exponent Exponent;
+
+ /** Returns whether there are any entries. */
+ bool empty() const {return size() == 0;}
+
+ /** Returns the number of entries. */
+ size_t size() const {return _size;}
+
+ /** Returns a string that describes the data structure. */
+ std::string getName() const;
+
+ /** Returns a reference to this object's configuration object. */
+ C& getConfiguration() {
+ return _tree.getConfiguration();
+ }
+
+ /** Returns a reference to this object's configuration object. */
+ const C& getConfiguration() const {
+ return const_cast<Tree&>(_tree).getConfiguration();
+ }
+
+ /** Removes all multiples of monomial. A duplicate counts
+ as a multiple. Returns true if any multiples were removed. */
+ bool removeMultiples(const Monomial& monomial) {
+ MATHIC_ASSERT(C::AllowRemovals);
+ if (!C::AllowRemovals)
+ throw std::logic_error("Removal request while removals disabled.");
+ DummyMultipleOutput out;
+ return removeMultiples(monomial, out);
+ }
+
+ /** Removes all multiples of monomial. A duplicate counts
+ as a multiple. Returns true if any multiples were removed.
+ Calls out.push_back(entry) for each entry that is removed. */
+ template<class MultipleOutput>
+ bool removeMultiples(const Monomial& monomial, MultipleOutput& out) {
+ MATHIC_ASSERT(C::AllowRemovals);
+ if (!C::AllowRemovals)
+ throw std::logic_error("Removal request while removals disabled.");
+ ExtMonoRef extMonomial(monomial, _divMaskCalculator, getConfiguration());
+ size_t removedCount = _tree.removeMultiples(extMonomial, out);
+ reportChanges(0, removedCount);
+ return removedCount > 0;
+ }
+
+ /** Calls out.proceed(entry) for each entry that monomial divides.
+ The method returns if proceed returns false, otherwise the
+ search for divisors proceeds. */
+ template<class Output>
+ void findAllMultiples(const Monomial& monomial, Output& out) {
+ ExtMonoRef extMonomial(monomial, _divMaskCalculator, getConfiguration());
+ _tree.findAllMultiples(extMonomial, out);
+ }
+
+ /** Calls out.proceed(entry) for each entry that monomial divides.
+ The method returns if proceed returns false, otherwise the
+ search for divisors proceeds. */
+ template<class Output>
+ void findAllMultiples(const Monomial& monomial, Output& output) const {
+ ConstEntryOutput<Output> constOutput(output);
+ const_cast<KDTree<C>&>(*this).findAllMultiples(monomial, constOutput);
+ }
+
+ /** Inserts entry into the data structure. Does NOT remove multiples
+ of entry and entry is inserted even if it is a multiple of another
+ entry. */
+ void insert(const Entry& entry) {
+ ExtEntry extEntry(entry, _divMaskCalculator, getConfiguration());
+ _tree.insert(extEntry);
+ reportChanges(1, 0);
+ }
+
+ /** Inserts the entries in the range [begin, end) into the data
+ structure. Does NOT remove multiples of entry and entry is inserted
+ even if it is a multiple of another entry.
+
+ The elements in the range [begin, end) may be rearranged by this
+ function, so the range must be mutable. If that is not acceptable,
+ call the one element insert method for each element. */
+ template<class Iter>
+ void insert(Iter begin, Iter end) {
+ if (begin == end)
+ return;
+ const size_t inserted = std::distance(begin, end);
+ if (!empty()) {
+ for (; begin != end; ++begin)
+ _tree.insert(*begin);
+ } else {
+ _tree.insert(begin, end);
+ // insert into empty container is equivalent to rebuild
+ resetNumberOfChangesTillRebuild();
+ }
+ reportChanges(inserted, 0);
+ }
+
+ /** Removes an element whose exponents are equal to monomial's. Returns
+ if there are no such monomials in the data structure. */
+ bool removeElement(const Monomial& monomial) {
+ MATHIC_ASSERT(C::AllowRemovals);
+ if (!C::AllowRemovals)
+ throw std::logic_error("Removal request while removals disabled.");
+ return _tree.removeElement(monomial);
+ }
+
+ /** Returns a pointer to an entry that divides monomial. Returns null if no
+ entries divide monomial. */
+ inline Entry* findDivisor(const Monomial& monomial) {
+ // todo: do this on extended monomials. requires cache to be extended.
+ const C& conf = getConfiguration();
+ if (conf.getUseDivisorCache() &&
+ _divisorCache != 0 &&
+ conf.divides(*_divisorCache, monomial))
+ return _divisorCache;
+
+ ExtMonoRef extMonomial(monomial, _divMaskCalculator, getConfiguration());
+ Entry* divisor = _tree.findDivisor(extMonomial);
+ if (conf.getUseDivisorCache() && divisor != 0)
+ _divisorCache = divisor;
+ return divisor;
+ }
+
+ /** Returns the position of a divisor of monomial. Returns null if no
+ entries divide monomial. */
+ inline const Entry* findDivisor(const Monomial& monomial) const {
+ return const_cast<KDTree<C>&>(*this).findDivisor(monomial);
+ }
+
+ /** Calls out.proceed(entry) for each entry that divides monomial.
+ The method returns if proceed returns false, otherwise the
+ search for divisors proceeds. */
+ template<class DivisorOutput>
+ void findAllDivisors(const Monomial& monomial, DivisorOutput& out) {
+ ExtMonoRef extMonomial(monomial, _divMaskCalculator, getConfiguration());
+ _tree.findAllDivisors(extMonomial, out);
+ }
+
+ /** Calls output.proceed(entry) for each entry that divides monomial.
+ The method returns if proceed returns false, otherwise the
+ search for divisors proceeds. */
+ template<class DivisorOutput>
+ void findAllDivisors(const Monomial& monomial, DivisorOutput& output) const {
+ ConstEntryOutput<DivisorOutput> constOutput(output);
+ const_cast<KDTree<C>&>(*this).findAllDivisors(monomial, constOutput);
+ }
+
+ /** Calls output.proceed(entry) for each entry.
+ The method returns if proceed returns false, otherwise the
+ search for divisors proceeds. */
+ template<class EntryOutput>
+ void forAll(EntryOutput& out) {
+ _tree.forAll(out);
+ }
+
+ /** Calls out.proceed(entry) for each entry.
+ The method returns if proceed returns false, otherwise the
+ search for divisors proceeds. */
+ template<class EntryOutput>
+ void forAll(EntryOutput& output) const {
+ ConstEntryOutput<EntryOutput> constOutput(output);
+ const_cast<KDTree<C>&>(*this).forAll(constOutput);
+ }
+
+ /** Removes all entries. Does not reset the configuration object. */
+ void clear() {
+ _tree.clear();
+ resetNumberOfChangesTillRebuild();
+ _tree.calc().rebuildDefault(getConfiguration());
+ }
+
+ /** Rebuilds the data structure. */
+ void rebuild() {
+ EntryRecorder recorder(memt::Arena::getArena(), size());
+ _tree.forAll(recorder);
+ _divMaskCalculator.rebuild
+ (recorder.begin(), recorder.end(), getConfiguration());
+ _tree.reset(recorder.begin(), recorder.end(), _divMaskCalculator);
+ resetNumberOfChangesTillRebuild();
+ }
+
+ /** Returns the number of bytes allocated by this object. Does not
+ include sizeof(*this), does not include any additional memory
+ that the configuration may have allocated and does not include
+ any memory that an Entry may point to. Does include
+ sizeof(Entry) as well as unused memory that is being kept to
+ avoid frequent allocations. */
+ size_t getMemoryUse() const {return _tree.getMemoryUse();}
+
+ private:
+ KDTree(const KDTree<C>&); // unavailable
+ void operator=(const KDTree<C>&); // unavailable
+
+ // For recording all entries in the tree using forAll.
+ class EntryRecorder {
+ public:
+ EntryRecorder(memt::Arena& arena, size_t capacity):
+ _entries(arena, capacity) {}
+ bool proceed(const Entry& entry) {
+ _entries.push_back(entry);
+ return true;
+ }
+ Entry* begin() {return _entries.begin();}
+ Entry* end() {return _entries.end();}
+
+ private:
+ memt::ArenaVector<Entry, true> _entries;
+ };
+
+ /// makes the parameter given to proceed be const.
+ template<class EntryOutput>
+ class ConstEntryOutput {
+ public:
+ ConstEntryOutput(EntryOutput& out): _out(out) {}
+ bool proceed(const Entry& entry) {return _out.proceed(entry);}
+ private:
+ EntryOutput& _out;
+ };
+
+ /// Ignores everything passed to it. */
+ class DummyMultipleOutput {
+ public:
+ void push_back(Entry& e) {}
+ };
+
+ void reportChanges(size_t additions, size_t removals);
+ void resetNumberOfChangesTillRebuild();
+ bool reportChangesRebuild(size_t additions, size_t removals);
+ size_t _changesTillRebuild; /// Update using reportChanges().
+
+ Entry* _divisorCache; /// The divisor in the previous query. Can be null.
+
+ // All DivMasks calculated using this.
+ typename Tree::DivMaskCalculator _divMaskCalculator;
+ Tree _tree;
+ size_t _size;
+ };
+
+ template<class C>
+ std::string KDTree<C>::getName() const {
+ std::stringstream out;
+ const C& conf = getConfiguration();
+ out << "KDTree(" << (C::PackedTree ? "packed" : "binary") << ')';
+ out << " leaf:" << C::LeafSize;
+ if (UseDivMask && conf.getDoAutomaticRebuilds()) {
+ out << " autob:" << conf.getRebuildRatio()
+ << '/' << conf.getRebuildMin();
+ }
+ out << (C::UseDivMask && !C::UseTreeDivMask ? " dmask" : "")
+ << (C::UseTreeDivMask ? " tree-dmask" : "")
+ << (conf.getSortOnInsert() ? " sort" : "")
+ << (conf.getUseDivisorCache() ? " cache" : "")
+ << (C::AllowRemovals ? "" : " no-removals");
+ return out.str();
+ }
+
+ template<class C>
+ void KDTree<C>::resetNumberOfChangesTillRebuild() {
+ const C& conf = getConfiguration();
+ if (conf.getUseDivisorCache())
+ _divisorCache = 0;
+ if (!conf.getDoAutomaticRebuilds())
+ return;
+ MATHIC_ASSERT(conf.getRebuildRatio() > 0);
+ _changesTillRebuild = std::max
+ (static_cast<size_t>(size() * conf.getRebuildRatio()),
+ conf.getRebuildMin());
+ }
+
+ template<class C>
+ void KDTree<C>::reportChanges(size_t additions, size_t removals) {
+ if (getConfiguration().getUseDivisorCache() && (additions | removals) != 0)
+ _divisorCache = 0;
+ if (reportChangesRebuild(additions, removals))
+ rebuild();
+ }
+
+ template<class C>
+ bool KDTree<C>::reportChangesRebuild(size_t additions, size_t removals) {
+ // note how negative value/overflow of _changesTillRebuild cannot
+ // happen this way.
+ MATHIC_ASSERT(removals <= size() + additions);
+ _size = (size() + additions) - removals;
+ if (!getConfiguration().getDoAutomaticRebuilds())
+ return false;
+ const size_t changesMadeCount = additions + removals;
+ if (_changesTillRebuild > changesMadeCount) {
+ _changesTillRebuild -= changesMadeCount;
+ return false;
+ } else
+ return true;
+ }
+}
+
+#endif
diff --git a/src/mathic/NameFactory.cpp b/src/mathic/NameFactory.cpp
new file mode 100755
index 0000000..74a2b00
--- /dev/null
+++ b/src/mathic/NameFactory.cpp
@@ -0,0 +1 @@
+#include "NameFactory.h"
diff --git a/src/mathic/NameFactory.h b/src/mathic/NameFactory.h
new file mode 100755
index 0000000..0eb210b
--- /dev/null
+++ b/src/mathic/NameFactory.h
@@ -0,0 +1,201 @@
+#ifndef MATHIC_NAME_FACTORY_GUARD
+#define MATHIC_NAME_FACTORY_GUARD
+
+#include "stdinc.h"
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <memory>
+#include "error.h"
+
+namespace mathic {
+ /** A NameFactory takes a name and then creates an instance of a class
+ that has been previously registered under that name. This is done
+ in a general way using templates.
+
+ None of this is very efficient currently. However, the interface can be
+ implemented much more efficiently if that becomes necessary.
+ */
+ template<class AbstractProduct>
+ class NameFactory {
+ public:
+ /** @param abstractName The name for those things that are being
+ generated in general. Used for error messages. */
+ NameFactory(const char* abstractName): _abstractName(abstractName) {}
+
+ typedef std::auto_ptr<AbstractProduct> (*FactoryFunction)();
+ void registerProduct(const std::string& name, FactoryFunction function);
+
+ /** Calls the function registered to the parameter name and returns
+ the result. Returns null if name has not been registered. */
+ std::auto_ptr<AbstractProduct>
+ createNullOnUnknown(const std::string& name) const;
+
+ /** Calls the function registered to the parameter name and returns
+ the result. Throws an exception if name has not been registered. */
+ std::auto_ptr<AbstractProduct> create(const std::string& name) const;
+
+ /** Inserts into names all registered names that have the indicated
+ prefix in lexicographic increasing order. */
+ void namesWithPrefix
+ (const std::string& prefix, std::vector<std::string>& names) const;
+
+ /** Returns the name of the kinds of things being created. */
+ std::string abstractProductName() const;
+
+ /** Returns true if no names have been registered. */
+ bool empty() const;
+
+ private:
+ typedef std::pair<std::string, FactoryFunction> Pair;
+ typedef typename std::vector<Pair>::const_iterator const_iterator;
+ std::vector<Pair> _pairs;
+ const std::string _abstractName;
+ };
+
+ /** Registers the given name to a function that
+ default-constructs a ConcreteProduct. */
+ template<class ConcreteProduct, class AbstractProduct>
+ void nameFactoryRegister
+ (NameFactory<AbstractProduct>& factory, const std::string& name);
+
+ /** Registers the name ConcreteProduct::staticName() to a function that
+ default-constructs a ConcreteProduct. */
+ template<class ConcreteProduct, class AbstractProduct>
+ void nameFactoryRegister
+ (NameFactory<AbstractProduct>& factory);
+
+ /** Registers the string returned by ConcreteProduct::staticName()
+ to a function that default-constructs a ConcreteProduct. */
+ template<class ConcreteProduct, class AbstractProduct>
+ void nameFactoryRegister(NameFactory<AbstractProduct>& factory);
+
+ /** Creates the unique product that has the indicated prefix, or
+ creates the actual product that has name equal to the indicated
+ prefix. Exceptions thrown are as for uniqueNamesWithPrefix(). */
+ template<class AbstractProduct>
+ std::auto_ptr<AbstractProduct> createWithPrefix
+ (const NameFactory<AbstractProduct>& factory, const std::string& prefix);
+
+ /** Returns the unique product name that has the indicated prefix, or
+ return prefix itself if it is the actual name of a product.
+
+ @exception UnknownNameException If no product has the indicated
+ prefix.
+
+ @exception AmbiguousNameException If more than one product has the
+ indicated prefix and the prefix is not the actual name of any
+ product. */
+ template<class AbstractProduct>
+ std::string uniqueNameWithPrefix
+ (const NameFactory<AbstractProduct>& factory, const std::string& prefix);
+
+
+ // **************************************************************
+ // These implementations have to be included here due
+ // to being templates.
+
+ template<class AbstractProduct>
+ std::auto_ptr<AbstractProduct> NameFactory<AbstractProduct>::
+ createNullOnUnknown(const std::string& name) const {
+ for (const_iterator it = _pairs.begin(); it != _pairs.end(); ++it)
+ if (it->first == name)
+ return it->second();
+ return std::auto_ptr<AbstractProduct>();
+ }
+
+ template<class AbstractProduct>
+ std::auto_ptr<AbstractProduct> NameFactory<AbstractProduct>::
+ create(const std::string& name) const {
+ std::auto_ptr<AbstractProduct> product = createNullOnUnknown(name);
+ if (product.get() == 0)
+ throwError<UnknownNameException>(
+ "Unknown " + abstractProductName() + " \"" + name + "\".");
+ return product;
+ }
+
+ template<class AbstractProduct>
+ void NameFactory<AbstractProduct>::
+ registerProduct(const std::string& name, FactoryFunction function) {
+ MATHIC_ASSERT(createNullOnUnknown(name).get() == 0); // no duplicate names
+ _pairs.push_back(Pair(name, function));
+ }
+
+ template<class AbstractProduct>
+ void NameFactory<AbstractProduct>::namesWithPrefix(
+ const std::string& prefix,
+ std::vector<std::string>& names
+ ) const {
+ for (const_iterator it = _pairs.begin(); it != _pairs.end(); ++it)
+ if (it->first.compare(0, prefix.size(), prefix) == 0)
+ names.push_back(it->first);
+ std::sort(names.begin(), names.end());
+ }
+
+ template<class AbstractProduct>
+ bool NameFactory<AbstractProduct>::empty() const {
+ return _pairs.empty();
+ }
+
+ template<class AbstractProduct>
+ std::string NameFactory<AbstractProduct>::abstractProductName() const {
+ return _abstractName;
+ }
+
+ template<class ConcreteProduct, class AbstractProduct>
+ void nameFactoryRegister(NameFactory<AbstractProduct>& factory) {
+ nameFactoryRegister<ConcreteProduct, AbstractProduct>
+ (factory, ConcreteProduct::staticName());
+ }
+
+ template<class ConcreteProduct, class AbstractProduct>
+ void nameFactoryRegister
+ (NameFactory<AbstractProduct>& factory, const std::string& name) {
+ // work-around for no local functions in old C++
+ struct HoldsFunction {
+ static std::auto_ptr<AbstractProduct> createConcreteProduct() {
+ return std::auto_ptr<AbstractProduct>(new ConcreteProduct());
+ }
+ };
+ factory.registerProduct(name, HoldsFunction::createConcreteProduct);
+ }
+
+ template<class AbstractProduct>
+ std::auto_ptr<AbstractProduct> createWithPrefix
+ (const NameFactory<AbstractProduct>& factory, const std::string& prefix) {
+ return factory.createNullOnUnknown(uniqueNameWithPrefix(factory, prefix));
+ }
+
+ template<class AbstractProduct>
+ std::string uniqueNameWithPrefix
+ (const NameFactory<AbstractProduct>& factory, const std::string& prefix) {
+ std::vector<std::string> names;
+ factory.namesWithPrefix(prefix, names);
+
+ // if exact string found, then use that one even if there are other
+ // prefix matches.
+ if (std::find(names.begin(), names.end(), prefix) != names.end()) {
+ names.clear();
+ names.push_back(prefix);
+ }
+
+ if (names.empty()) {
+ throwError<UnknownNameException>
+ ("No " + factory.abstractProductName() +
+ " has the prefix \"" + prefix + "\".");
+ }
+
+ if (names.size() >= 2) {
+ std::string errorMsg = "More than one " + factory.abstractProductName() +
+ " has prefix \"" + prefix + "\":\n ";
+ for (size_t name = 0; name < names.size(); ++name)
+ errorMsg += ' ' + names[name];
+ throwError<AmbiguousNameException>(errorMsg);
+ }
+
+ MATHIC_ASSERT(names.size() == 1);
+ return names.back();
+ }
+}
+
+#endif
diff --git a/src/mathic/PackedKDTree.h b/src/mathic/PackedKDTree.h
new file mode 100755
index 0000000..374807b
--- /dev/null
+++ b/src/mathic/PackedKDTree.h
@@ -0,0 +1,760 @@
+#ifndef MATHIC_PACKED_K_D_TREE_GUARD
+#define MATHIC_PACKED_K_D_TREE_GUARD
+
+#include "stdinc.h"
+#include "DivMask.h"
+#include "KDEntryArray.h"
+#include <memtailor.h>
+#include <ostream>
+
+namespace mathic {
+ template<class C>
+ class PackedKDTree {
+ public:
+ typedef typename C::Monomial Monomial;
+ typedef typename C::Entry Entry;
+ typedef typename C::Exponent Exponent;
+ typedef typename DivMask::Extender<Entry, C::UseDivMask> ExtEntry;
+ typedef typename DivMask::Extender<const Monomial&,C::UseDivMask> ExtMonoRef;
+ typedef typename DivMask::Calculator<C> DivMaskCalculator;
+
+ struct ExpOrder {
+ ExpOrder(size_t var, const C& conf): _var(var), _conf(conf) {}
+ bool operator()(const ExtEntry& a, const ExtEntry& b) const {
+ return _conf.getExponent(a.get(), _var) < _conf.getExponent(b.get(), _var);
+ }
+ private:
+ const size_t _var;
+ const C& _conf;
+ };
+
+ private:
+ typedef C Configuration;
+ static const bool UseDivMask = C::UseDivMask;
+
+ class Node {
+ public:
+ static Node* makeNode(memt::Arena& arena, const C& conf) {
+ return new (arena.alloc(sizeOf(0)))
+ Node(arena, conf);
+ }
+
+ template<class Iter>
+ static Node* makeNode(Iter begin, Iter end, memt::Arena& arena,
+ const C& conf, size_t childCount) {
+ return new (arena.alloc(sizeOf(childCount)))
+ Node(begin, end, arena, conf, childCount);
+ }
+
+ template<class Iter>
+ static Node* makeNode(Iter begin, Iter end, memt::Arena& arena,
+ const DivMaskCalculator& calc, const C& conf, size_t childCount) {
+ return new (arena.alloc(sizeOf(childCount)))
+ Node(begin, end, arena, calc, conf, childCount);
+ }
+
+ static size_t sizeOf(size_t childCount) {
+ if (childCount > 0)
+ --childCount; // array has size 1, so one element already there
+ return sizeof(Node) + childCount * sizeof(Child);
+ }
+
+ struct Child : public mathic::DivMask::HasDivMask<C::UseTreeDivMask> {
+ size_t var;
+ Exponent exponent;
+ Node* node;
+ };
+ typedef Child* iterator;
+ typedef Child const* const_iterator;
+ iterator childBegin() {return _childrenMemoryBegin;}
+ const_iterator childBegin() const {return _childrenMemoryBegin;}
+ iterator childEnd() {return _childrenEnd;}
+ const_iterator childEnd() const {return _childrenEnd;}
+
+ bool hasChildren() const {return childBegin() != childEnd();}
+ template<class ME> // ME is MonomialOrEntry
+ bool inChild(const_iterator child, const ME me, const C& conf) const {
+ return child->exponent < conf.getExponent(me, child->var);
+ }
+
+ mathic::KDEntryArray<C, ExtEntry>& entries() {return _entries;}
+ const KDEntryArray<C, ExtEntry>& entries() const {return _entries;}
+
+ Node* splitInsert(
+ const ExtEntry& extEntry,
+ Child* childFromParent,
+ memt::Arena& arena,
+ const C& conf);
+
+#ifdef MATHIC_DEBUG
+ bool debugIsValid() const;
+#endif
+
+ private:
+ Node(const Node&); // unavailable
+ void operator=(const Node&); // unavailable
+
+ Node(memt::Arena& arena, const C& conf);
+
+ template<class Iter>
+ Node(Iter begin, Iter end, memt::Arena& arena,
+ const C& conf, size_t childCount);
+
+ template<class Iter>
+ Node(Iter begin, Iter end, memt::Arena& arena,
+ const DivMaskCalculator& calc, const C& conf, size_t childCount);
+
+ class SplitEqualOrLess;
+
+ KDEntryArray<C, ExtEntry> _entries;
+ // Array has size 1 to appease compiler since size 0 produces warnings
+ // or errors. Actual size can be greater if more memory has been
+ // allocated for the node than sizeof(Node).
+ Child* _childrenEnd; // points into _childrenMemoryBegin
+ Child _childrenMemoryBegin[1];
+ };
+
+ public:
+ PackedKDTree(const C& configuration);
+ ~PackedKDTree();
+
+ template<class MultipleOutput>
+ size_t removeMultiples(const ExtMonoRef& monomial, MultipleOutput& out);
+
+ bool removeElement(const Monomial& monomial);
+
+ void insert(const ExtEntry& entry);
+
+ template<class Iter>
+ void reset(Iter begin, Iter end, const DivMaskCalculator& calc);
+
+ inline Entry* findDivisor(const ExtMonoRef& monomial);
+
+ template<class DivisorOutput>
+ inline void findAllDivisors
+ (const ExtMonoRef& monomial, DivisorOutput& out);
+
+ template<class DivisorOutput>
+ inline void findAllMultiples
+ (const ExtMonoRef& monomial, DivisorOutput& out);
+
+ template<class EntryOutput>
+ void forAll(EntryOutput& out);
+
+ void clear();
+
+ size_t getMemoryUse() const;
+
+ void print(std::ostream& out) const;
+
+ C& getConfiguration() {return _conf;}
+
+#ifdef MATHIC_DEBUG
+ bool debugIsValid() const;
+#endif
+
+ private:
+ PackedKDTree(const PackedKDTree<C>&); // unavailable
+ void operator=(const PackedKDTree<C>&); // unavailable
+
+ template<class Iter>
+ struct InsertTodo {
+ Iter begin;
+ Iter end;
+ Exponent exp;
+ size_t var;
+ typename Node::Child* fromParent;
+ };
+
+ memt::Arena _arena; // Everything permanent allocated from here.
+ C _conf; // User supplied configuration.
+ mutable std::vector<Node*> _tmp; // For navigating the tree.
+ Node* _root; // Root of the tree. Can be null!
+ };
+
+ template<class C>
+ PackedKDTree<C>::PackedKDTree(const C& configuration):
+ _conf(configuration), _root(0) {
+ MATHIC_ASSERT(C::LeafSize > 0);
+ MATHIC_ASSERT(debugIsValid());
+ }
+
+ template<class C>
+ PackedKDTree<C>::~PackedKDTree() {
+ clear();
+ }
+
+ template<class C>
+ PackedKDTree<C>::Node::Node(memt::Arena& arena, const C& conf):
+ _entries(arena, conf) {
+ _childrenEnd = childBegin();
+ }
+
+ template<class C>
+ template<class Iter>
+ PackedKDTree<C>::Node::Node(
+ Iter begin,
+ Iter end,
+ memt::Arena& arena,
+ const C& conf,
+ size_t childCount):
+ _entries(begin, end, arena, conf) {
+ _childrenEnd = childBegin() + childCount;
+ }
+
+ template<class C>
+ template<class Iter>
+ PackedKDTree<C>::Node::Node(
+ Iter begin,
+ Iter end,
+ memt::Arena& arena,
+ const DivMaskCalculator& calc,
+ const C& conf,
+ size_t childCount):
+ _entries(begin, end, arena, calc, conf) {
+ _childrenEnd = childBegin() + childCount;
+ }
+
+ template<class C>
+ template<class MO>
+ size_t PackedKDTree<C>::removeMultiples(
+ const ExtMonoRef& extMonomial,
+ MO& out
+ ) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return 0;
+ size_t removedCount = 0;
+ Node* node = _root;
+ while (true) {
+ for (typename Node::const_iterator it = node->childBegin();
+ it != node->childEnd(); ++it) {
+ _tmp.push_back(it->node);
+ if (node->inChild(it, extMonomial.get(), _conf))
+ goto stopped;
+ }
+ removedCount += node->entries().removeMultiples(extMonomial, out, _conf);
+stopped:;
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ MATHIC_ASSERT(debugIsValid());
+ return removedCount;
+ }
+
+ template<class C>
+ bool PackedKDTree<C>::removeElement(const Monomial& monomial) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return false;
+ Node* node = _root;
+
+ typename Node::iterator child = node->childBegin();
+ while (child != node->childEnd()) {
+ if (node->inChild(child, monomial, _conf)) {
+ node = child->node;
+ child = node->childBegin();
+ } else
+ ++child;
+ }
+ const bool value = node->entries().removeElement(monomial, _conf);
+ MATHIC_ASSERT(debugIsValid());
+ return value;
+ }
+
+ template<class C>
+ void PackedKDTree<C>::insert(const ExtEntry& extEntry) {
+ MATHIC_ASSERT(debugIsValid());
+ // find node in which to insert extEntry
+ typename Node::Child* parentChild = 0;
+ if (_root == 0)
+ _root = Node::makeNode(_arena, _conf);
+ Node* node = _root;
+ typename Node::iterator child = node->childBegin();
+ while (true) {
+ if (child == node->childEnd()) {
+ MATHIC_ASSERT(node->entries().size() <= C::LeafSize);
+ if (node->entries().size() < C::LeafSize)
+ node->entries().insert(extEntry, _conf);
+ else { // split full node
+ node = node->splitInsert(extEntry, parentChild, _arena, _conf);
+ if (parentChild == 0)
+ _root = node;
+ }
+ break;
+ }
+ if (C::UseTreeDivMask)
+ child->updateToLowerBound(extEntry);
+ if (node->inChild(child, extEntry.get(), _conf)) {
+ parentChild = &*child;
+ node = child->node;
+ child = node->childBegin();
+ } else
+ ++child;
+ }
+ MATHIC_ASSERT(debugIsValid());
+ }
+
+ template<class C>
+ template<class Iter>
+ void PackedKDTree<C>::reset(Iter insertBegin, Iter insertEnd, const DivMaskCalculator& calc) {
+ clear();
+ if (insertBegin == insertEnd)
+ return;
+
+ typedef InsertTodo<Iter> Task;
+ typedef std::vector<Task> TaskCont;
+ TaskCont todo;
+ TaskCont children;
+
+ {
+ Task initialTask;
+ initialTask.begin = insertBegin;
+ initialTask.end = insertEnd;
+ initialTask.var = static_cast<size_t>(-1);
+ initialTask.fromParent = 0;
+ todo.push_back(initialTask);
+ }
+ while (!todo.empty()) {
+ Iter begin = todo.back().begin;
+ Iter end = todo.back().end;
+ size_t var = todo.back().var;
+ typename Node::Child* fromParent = todo.back().fromParent;
+ if (fromParent != 0) {
+ fromParent->var = var;
+ fromParent->exponent = todo.back().exp;
+ }
+ todo.pop_back();
+
+ // split off children until reaching few enough entries
+ while (C::LeafSize < static_cast<size_t>(std::distance(begin, end))) {
+ Task child;
+ Iter middle = KDEntryArray<C, ExtEntry>::
+ split(begin, end, var, child.exp, _conf);
+ MATHIC_ASSERT(begin < middle && middle < end);
+ MATHIC_ASSERT(var < _conf.getVarCount());
+ child.begin = middle;
+ child.end = end;
+ child.var = var;
+ children.push_back(child);
+ // now operate on the equal-or-less part of the range
+ end = middle;
+ }
+ Node* node = Node::makeNode
+ (begin, end, _arena, calc, _conf, children.size());
+ if (_root == 0)
+ _root = node;
+ if (fromParent != 0)
+ fromParent->node = node;
+ for (size_t child = 0; child < children.size(); ++child) {
+ children[child].fromParent = &*(node->childBegin() + child);
+ todo.push_back(children[child]);
+ }
+ children.clear();
+ }
+ MATHIC_ASSERT(_root != 0);
+
+ if (C::UseTreeDivMask) {
+ // record nodes in tree using breadth first search
+ typedef std::vector<Node*> NodeCont;
+ NodeCont nodes;
+ nodes.push_back(_root);
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ Node* node = nodes[i];
+ for (typename Node::iterator child = node->childBegin();
+ child != node->childEnd(); ++child)
+ nodes.push_back(child->node);
+ }
+ // compute div masks in reverse order of breath first search
+ typename NodeCont::reverse_iterator it = nodes.rbegin();
+ typename NodeCont::reverse_iterator end = nodes.rend();
+ for (; it != end; ++it) {
+ Node* node = *it;
+ typedef std::reverse_iterator<typename Node::iterator> riter;
+ riter rbegin = riter(node->childEnd());
+ riter rend = riter(node->childBegin());
+ for (riter child = rbegin; child != rend; ++child) {
+ child->resetDivMask();
+ if (child == rbegin)
+ child->updateToLowerBound(node->entries());
+ else {
+ riter prev = child;
+ --prev;
+ child->updateToLowerBound(*prev);
+ }
+ if (child->node->hasChildren())
+ child->updateToLowerBound(*child->node->childBegin());
+ else
+ child->updateToLowerBound(child->node->entries());
+ }
+ ASSERT(node->debugIsValid());
+ }
+ }
+ MATHIC_ASSERT(debugIsValid());
+ }
+
+ template<class C>
+ typename PackedKDTree<C>::Entry* PackedKDTree<C>::findDivisor
+ (const ExtMonoRef& extMonomial) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return 0;
+ Node* node = _root;
+ while (true) {
+ // record relevant children for later processing
+ for (typename Node::const_iterator it = node->childBegin();
+ it != node->childEnd(); ++it) {
+ if (C::UseTreeDivMask &&
+ !it->getDivMask().canDivide(extMonomial.getDivMask()))
+ goto next;
+ if (node->inChild(it, extMonomial.get(), _conf))
+ _tmp.push_back(it->node);
+ }
+
+ // look for divisor in entries of node
+ {
+ typename KDEntryArray<C, ExtEntry>::iterator it =
+ node->entries().findDivisor(extMonomial, _conf);
+ if (it != node->entries().end()) {
+ MATHIC_ASSERT(_conf.divides(it->get(), extMonomial.get()));
+ _tmp.clear();
+ return &it->get();
+ }
+ }
+
+next:
+ // grab next node to process
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ return 0;
+ }
+
+ template<class C>
+ template<class DO>
+ void PackedKDTree<C>::findAllDivisors(
+ const ExtMonoRef& extMonomial,
+ DO& output
+ ) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return;
+ Node* node = _root;
+ while (true) {
+ for (typename Node::const_iterator it = node->childBegin();
+ it != node->childEnd(); ++it) {
+ if (C::UseTreeDivMask &&
+ !it->getDivMask().canDivide(extMonomial.getDivMask()))
+ goto next; // div mask rules this sub tree out
+ if (node->inChild(it, extMonomial.get(), _conf))
+ _tmp.push_back(it->node);
+ }
+ if (!node->entries().findAllDivisors(extMonomial, output, _conf)) {
+ _tmp.clear();
+ break;
+ }
+next:
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ }
+
+ template<class C>
+ template<class DO>
+ void PackedKDTree<C>::findAllMultiples(
+ const ExtMonoRef& extMonomial,
+ DO& output
+ ) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return;
+ Node* node = _root;
+ while (true) {
+ for (typename Node::const_iterator it = node->childBegin();
+ it != node->childEnd(); ++it) {
+ _tmp.push_back(it->node);
+ if (node->inChild(it, extMonomial.get(), _conf))
+ goto next;
+ }
+ if (!node->entries().findAllMultiples(extMonomial, output, _conf)) {
+ _tmp.clear();
+ break;
+ }
+next:
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ }
+
+ template<class C>
+ template<class EO>
+ void PackedKDTree<C>::forAll(EO& output) {
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return;
+ Node* node = _root;
+ while (true) {
+ if (!node->entries().forAll(output)) {
+ _tmp.clear();
+ break;
+ }
+ for (typename Node::iterator it = node->childBegin();
+ it != node->childEnd(); ++it)
+ _tmp.push_back(it->node);
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ }
+
+ template<class C>
+ void PackedKDTree<C>::clear() {
+ MATHIC_ASSERT(_tmp.empty());
+ // Call Entry destructors
+ if (_root != 0)
+ _tmp.push_back(_root);
+ while (!_tmp.empty()) {
+ Node* node = _tmp.back();
+ _tmp.pop_back();
+ node->entries().clear(); // calls destructors
+ for (typename Node::iterator it = node->childBegin();
+ it != node->childEnd(); ++it)
+ _tmp.push_back(it->node);
+ }
+ _arena.freeAllAllocs();
+ _root = 0;
+ }
+
+ template<class C>
+ size_t PackedKDTree<C>::getMemoryUse() const {
+ // todo: not accurate
+ size_t sum = _arena.getMemoryUse();
+ sum += _tmp.capacity() * sizeof(_tmp.front());
+ return sum;
+ }
+
+ template<class C>
+ void PackedKDTree<C>::print(std::ostream& out) const {
+ out << "<<<<<<<< PackedKDTree >>>>>>>>\n";
+ MATHIC_ASSERT(_tmp.empty());
+ if (_root == 0)
+ return;
+ Node* node = _root;
+ while (true) {
+ out << "**** Node " << node << "\nchildren:\n";
+ for (typename Node::iterator it = node->childBegin();
+ it != node->childEnd(); ++it) {
+ _tmp.push_back(it->node);
+ out << "Child " << ((it - node->childBegin()) + 1) << ": "
+ << '>' << (it->var + 1) << '^' << it->exponent
+ << ' ' << it->node << '\n';
+ }
+ for (size_t i = 0; i < node->entries().size(); ++i) {
+ out << "Entry " << (i + 1) << ": "
+ << node->entries().begin()[i].get() << '\n';
+ }
+ out << '\n';
+ if (_tmp.empty())
+ break;
+ node = _tmp.back();
+ _tmp.pop_back();
+ }
+ MATHIC_ASSERT(_tmp.empty());
+ }
+
+#ifdef MATHIC_DEBUG
+ template<class C>
+ bool PackedKDTree<C>::debugIsValid() const {
+ //print(std::cerr); std::cerr << std::flush;
+ MATHIC_ASSERT(_tmp.empty());
+ MATHIC_ASSERT(!_conf.getDoAutomaticRebuilds() || _conf.getRebuildRatio() > 0);
+ if (_root == 0)
+ return true;
+
+ // record all nodes
+ std::vector<Node*> nodes;
+ nodes.push_back(_root);
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ Node* node = nodes[i];
+ ASSERT(node->entries().debugIsValid());
+ for (typename Node::iterator it = node->childBegin();
+ it != node->childEnd(); ++it) {
+ MATHIC_ASSERT(it->var < _conf.getVarCount());
+ MATHIC_ASSERT(!C::UseTreeDivMask ||
+ it->canDivide(node->entries()));
+ nodes.push_back(it->node);
+ }
+ }
+
+ // check the recorded nodes
+ MATHIC_ASSERT(_tmp.empty());
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ Node* ancestor = nodes[i];
+
+ for (typename Node::iterator ancestorIt = ancestor->childBegin();
+ ancestorIt != ancestor->childEnd(); ++ancestorIt) {
+ MATHIC_ASSERT(_tmp.empty());
+ size_t var = ancestorIt->var;
+ Exponent exp = ancestorIt->exponent;
+ // check strictly greater than subtree
+ _tmp.push_back(ancestorIt->node);
+ while (!_tmp.empty()) {
+ Node* node = _tmp.back();
+ _tmp.pop_back();
+ for (typename Node::iterator it = node->childBegin();
+ it != node->childEnd(); ++it) {
+ MATHIC_ASSERT(!C::UseTreeDivMask || ancestorIt->canDivide(*it));
+ _tmp.push_back(it->node);
+ }
+ MATHIC_ASSERT(node->entries().
+ allStrictlyGreaterThan(var, exp, _conf));
+ MATHIC_ASSERT(!C::UseTreeDivMask ||
+ ancestorIt->canDivide(node->entries()));
+ }
+ // check less than or equal to sub tree.
+ MATHIC_ASSERT(ancestor->entries().
+ allLessThanOrEqualTo(var, exp, _conf));
+ // go through the rest of the children
+ typename Node::iterator restIt = ancestorIt;
+ for (++restIt; restIt != ancestor->childEnd(); ++restIt) {
+ MATHIC_ASSERT(!C::UseTreeDivMask || ancestorIt->canDivide(*restIt));
+ _tmp.push_back(restIt->node);
+ }
+ while (!_tmp.empty()) {
+ Node* node = _tmp.back();
+ _tmp.pop_back();
+ for (typename Node::iterator it = node->childBegin();
+ it != node->childEnd(); ++it) {
+ MATHIC_ASSERT(!C::UseTreeDivMask || ancestorIt->canDivide(*it));
+ _tmp.push_back(it->node);
+ }
+ MATHIC_ASSERT(node->entries().
+ allLessThanOrEqualTo(var, exp, _conf));
+ MATHIC_ASSERT(!C::UseTreeDivMask ||
+ ancestorIt->canDivide(node->entries()));
+ }
+ }
+ }
+ return true;
+ }
+#endif
+
+ template<class C>
+ class PackedKDTree<C>::Node::SplitEqualOrLess {
+ public:
+ typedef typename C::Exponent Exponent;
+ typedef typename C::Entry Entry;
+ SplitEqualOrLess(size_t var, const Exponent& exp, const C& conf):
+ _var(var), _exp(exp), _conf(conf) {}
+ bool operator()(const Entry& entry) const {
+ return !(_exp < _conf.getExponent(entry, _var));
+ }
+ private:
+ size_t _var;
+ const Exponent& _exp;
+ const C& _conf;
+ };
+
+ template<class C>
+ typename PackedKDTree<C>::Node* PackedKDTree<C>::Node::splitInsert(
+ const ExtEntry& extEntry,
+ Child* childFromParent,
+ memt::Arena& arena,
+ const C& conf
+ ) {
+ MATHIC_ASSERT(conf.getVarCount() > 0);
+ MATHIC_ASSERT(entries().size() > 0);
+ size_t var;
+ if (hasChildren())
+ var = (childEnd() - 1)->var;
+ else if (childFromParent != 0)
+ var = childFromParent->var;
+ else
+ var = static_cast<size_t>(-1);
+ typename C::Exponent exp;
+
+ // there is not room to add another child, so make a
+ // new Node with more space and put the Node we are splitting
+ // off into the vacated space. It will fit as it has no
+ // children at all.
+
+ typename KDEntryArray<C, ExtEntry>::iterator middle =
+ KDEntryArray<C, ExtEntry>::split
+ (entries().begin(), entries().end(), var, exp, conf, &extEntry);
+
+ // ** copy relevant part of *this into new space
+ Node* copied = makeNode(entries().begin(), middle, arena, conf,
+ std::distance(childBegin(), childEnd()) + 1);
+ std::copy(childBegin(), childEnd(), copied->childBegin());
+ Child& newChild = *(copied->childEnd() - 1);
+ newChild.var = var;
+ newChild.exponent = exp;
+ newChild.node = this;
+ if (childFromParent != 0)
+ childFromParent->node = copied;
+ if (C::UseTreeDivMask) {
+ newChild.resetDivMask();
+ newChild.updateToLowerBound(entries());
+ newChild.updateToLowerBound(extEntry);
+ }
+
+ // ** fix up remaining part of *this to be the child of copied
+ // OK to call std::copy as begin is not in the range [middle, end).
+ std::copy(middle, entries().end(), entries().begin());
+ const size_t targetSize = std::distance(middle, entries().end());
+ while (entries().size() > targetSize)
+ entries().pop_back();
+ if (conf.getSortOnInsert())
+ std::sort(entries().begin(), entries().end(), Comparer<C>(conf));
+ if (C::UseTreeDivMask)
+ entries().recalculateTreeDivMask();
+ _childrenEnd = childBegin();
+
+ if (copied->inChild(copied->childEnd() - 1, extEntry.get(), conf))
+ entries().insert(extEntry, conf);
+ else
+ copied->entries().insert(extEntry, conf);
+
+ MATHIC_ASSERT(debugIsValid());
+ MATHIC_ASSERT(copied->debugIsValid());
+
+ return copied;
+ }
+
+#ifdef MATHIC_DEBUG
+ template<class C>
+ bool PackedKDTree<C>::Node::debugIsValid() const {
+ ASSERT(entries().debugIsValid());
+ ASSERT(childBegin() <= childEnd());
+ if (C::UseTreeDivMask) {
+ for (const_iterator child = childBegin(); child != childEnd(); ++child) {
+ if (child != childEnd() - 1)
+ MATHIC_ASSERT(child->canDivide(*(child + 1)));
+ else
+ MATHIC_ASSERT(child->canDivide(entries()));
+ if (child->node->hasChildren())
+ MATHIC_ASSERT(child->canDivide(*child->node->childBegin()));
+ else
+ MATHIC_ASSERT(child->canDivide(child->node->entries()));
+ }
+ }
+ return true;
+ }
+#endif
+}
+
+#endif
diff --git a/src/mathic/StlSet.h b/src/mathic/StlSet.h
new file mode 100755
index 0000000..9f1609f
--- /dev/null
+++ b/src/mathic/StlSet.h
@@ -0,0 +1,68 @@
+#ifndef MATHIC_STL_SET_GUARD
+#define MATHIC_STL_SET_GUARD
+
+#include "stdinc.h"
+#include <set>
+#include <string>
+#include <ostream>
+
+namespace mathic {
+ template<class C>
+ class StlSet {
+ public:
+ typedef C Configuration;
+ typedef typename Configuration::Entry Entry;
+
+ StlSet(const Configuration& configuration):
+ _conf(configuration), _set(Cmp(&_conf)) {}
+ Configuration& getConfiguration() {return _conf;}
+ const Configuration& getConfiguration() const {return _conf;}
+
+ std::string getName() const {return "stlset";}
+ void push(Entry entry) {_set.insert(entry);}
+ void push(const Entry* begin, const Entry* end) {
+ for (; begin != end; ++begin)
+ push(*begin);
+ }
+ Entry pop() {
+ Entry top = *_set.begin();
+ _set.erase(_set.begin());
+ return top;
+ }
+ Entry top() {
+ return *_set.begin();
+ }
+ bool empty() const {return _set.empty();}
+ void print(std::ostream& out) const {
+ out << getName() << ":\n";
+ for (typename std::multiset<Entry, Cmp>::const_iterator it = _set.begin();
+ it != _set.end(); ++it)
+ out << ' ' << *it;
+ out << '\n';
+ }
+
+ /** This is necessarily an estimate since there is no
+ way to tell how much memory a std::multiset is using. */
+ size_t getMemoryUse() const {
+ const size_t bytesPerItemEstimate =
+ 2 * sizeof(void*) + // assume binary tree with left and right pointers
+ sizeof(void*) + // assume minimal overhead in the allocator behind new
+ sizeof(int) + // assume some overhead to maintain balance in tree
+ sizeof(Entry); // assume data payload
+ return _set.size() * bytesPerItemEstimate;
+ }
+
+ private:
+ Configuration _conf;
+ struct Cmp {
+ Cmp(const Configuration* conf): _conf(conf) {}
+ bool operator()(const Entry& a, const Entry& b) {
+ return _conf->cmpLessThan(_conf->compare(b, a));
+ }
+ const Configuration* _conf; // should be &, but gcc complains
+ };
+ std::multiset<Entry, Cmp> _set;
+ };
+}
+
+#endif
diff --git a/src/mathic/StringParameter.cpp b/src/mathic/StringParameter.cpp
new file mode 100755
index 0000000..84f35e7
--- /dev/null
+++ b/src/mathic/StringParameter.cpp
@@ -0,0 +1,22 @@
+#include "StringParameter.h"
+
+namespace mathic {
+ StringParameter::StringParameter(const std::string& name,
+ const std::string& description,
+ const std::string& defaultValue):
+ CliParameter(name, description),
+ _value(defaultValue) {
+ }
+
+ std::string StringParameter::argumentType() const {
+ return "STRING";
+ }
+
+ std::string StringParameter::valueAsString() const {
+ return _value;
+ }
+
+ void StringParameter::processArgument(const std::string& argument) {
+ _value = argument;
+ }
+}
diff --git a/src/mathic/StringParameter.h b/src/mathic/StringParameter.h
new file mode 100755
index 0000000..f94f6f1
--- /dev/null
+++ b/src/mathic/StringParameter.h
@@ -0,0 +1,32 @@
+#ifndef MATHIC_STRING_PARAMETER_GUARD
+#define MATHIC_STRING_PARAMETER_GUARD
+
+#include "stdinc.h"
+#include "CliParameter.h"
+#include <utility>
+#include <string>
+
+namespace mathic {
+ class StringParameter : public CliParameter {
+ public:
+ StringParameter(const std::string& name,
+ const std::string& description,
+ const std::string& defaultValue);
+
+ const std::string& value() const {return _value;}
+ void setValue(const std::string& value) {_value = value;}
+
+ operator const std::string&() const {return value();}
+ void operator=(const std::string& value) {setValue(value);}
+ bool operator==(const std::string& str) const {return value() == str;}
+
+ virtual std::string argumentType() const;
+ virtual std::string valueAsString() const;
+ virtual void processArgument(const std::string& argument);
+
+ private:
+ std::string _value;
+ };
+}
+
+#endif
diff --git a/src/mathic/Timer.cpp b/src/mathic/Timer.cpp
new file mode 100644
index 0000000..9e221c9
--- /dev/null
+++ b/src/mathic/Timer.cpp
@@ -0,0 +1,51 @@
+#include "Timer.h"
+
+namespace mathic {
+ unsigned long Timer::getMilliseconds() const {
+ const double floatSpan = clock() - _clocksAtReset;
+ const double floatMilliseconds = 1000 * (floatSpan / CLOCKS_PER_SEC);
+ unsigned long milliseconds = static_cast<unsigned long>(floatMilliseconds);
+ if (floatMilliseconds - milliseconds >= 0.5)
+ ++milliseconds;
+ return milliseconds;
+ }
+
+ void Timer::print(FILE* out) const {
+ unsigned long milliseconds = getMilliseconds();
+ unsigned long seconds = milliseconds / 1000;
+ unsigned long minutes = seconds / 60;
+ unsigned long hours = minutes / 60;
+
+ milliseconds %= 1000;
+ seconds %= 60;
+ minutes %= 60;
+
+ fputc('(', out);
+ if (hours != 0)
+ fprintf(out, "%luh", hours);
+ if (minutes != 0 || hours != 0)
+ fprintf(out, "%lum", minutes);
+ fprintf(out, "%lu.%03lus)", seconds, milliseconds);
+ }
+
+ void Timer::print(std::ostream& out) const {
+ unsigned long milliseconds = getMilliseconds();
+ unsigned long seconds = milliseconds / 1000;
+ unsigned long minutes = seconds / 60;
+ unsigned long hours = minutes / 60;
+
+ milliseconds %= 1000;
+ seconds %= 60;
+ minutes %= 60;
+
+ if (hours != 0)
+ out << hours << 'h';
+ if (minutes != 0 || hours != 0)
+ out << minutes << 'm';
+ out << seconds << '.';
+ out << (milliseconds / 100);
+ out << ((milliseconds / 10) % 10);
+ out << (milliseconds % 10);
+ out << "s";
+ }
+}
diff --git a/src/mathic/Timer.h b/src/mathic/Timer.h
new file mode 100644
index 0000000..d00e325
--- /dev/null
+++ b/src/mathic/Timer.h
@@ -0,0 +1,44 @@
+#ifndef MATHIC_TIMER_GUARD
+#define MATHIC_TIMER_GUARD
+
+#include "stdinc.h"
+#include <ctime>
+#include <cstdio>
+#include <ostream>
+
+namespace mathic {
+ /** Measures spans of CPU time.
+
+ The internal record of time can overflow quickly. If
+ clock_t is 32 bits unsigned and CLOCKS_PER_TIC is one million
+ then overflow will occur after 71 minutes. */
+ class Timer {
+ public:
+ Timer() {reset();}
+
+ /** Resets the amount of elapsed CPU time to zero. */
+ void reset() {_clocksAtReset = std::clock();}
+
+ /** Returns the number of CPU milliseconds since the last reset.
+ See class description for time span overflow limitations. */
+ unsigned long getMilliseconds() const;
+
+ /** Prints the elapsed time in a human readable format. See
+ class description for time span overflow limitations. */
+ void print(FILE* out) const;
+
+ /** Prints the elapsed time in a human readable format. See
+ class description for time span overflow limitations. */
+ void print(std::ostream& out) const;
+
+ private:
+ std::clock_t _clocksAtReset;
+ };
+
+ inline std::ostream& operator<<(std::ostream& out, const Timer& timer) {
+ timer.print(out);
+ return out;
+ }
+}
+
+#endif
diff --git a/src/mathic/TourTree.h b/src/mathic/TourTree.h
new file mode 100755
index 0000000..9256c12
--- /dev/null
+++ b/src/mathic/TourTree.h
@@ -0,0 +1,261 @@
+#ifndef MATHIC_TOUR_TREE_GUARD
+#define MATHIC_TOUR_TREE_GUARD
+
+#include "stdinc.h"
+#include "ComTree.h"
+#include <string>
+#include <vector>
+
+namespace mathic {
+ template<class C>
+ class TourTree {
+ public:
+ typedef C Configuration;
+ typedef typename Configuration::Entry Entry;
+
+ TourTree(const Configuration& configuration);
+ Configuration& getConfiguration() {return _conf;}
+ const Configuration& getConfiguration() const {return _conf;}
+
+ std::string getName() const;
+ void push(Entry entry);
+ template<class It>
+ void push(It begin, It end);
+ Entry pop();
+ Entry top() const;
+ bool empty() const {return _tree.empty();}
+ void print(std::ostream& out) const;
+
+ void decreaseTop(Entry newEntry);
+
+ template<class T>
+ void forAll(T& t) const {
+ typedef typename std::vector<Player>::const_iterator Iter;
+ Iter end = _players.end();
+ for (Iter it = _players.begin(); it != end; ++it)
+ if (!t.proceed(it->entry))
+ return;
+ }
+
+ template<class T>
+ void forAll(T& t) {
+ typedef typename std::vector<Player>::iterator Iter;
+ Iter end = _players.end();
+ for (Iter it = _players.begin(); it != end; ++it)
+ if (!t.proceed(it->entry))
+ return;
+ }
+
+ void clear();
+
+ size_t getMemoryUse() const;
+
+ private:
+ class Player;
+ typedef ComTree<Player*, C::fastIndex> Tree;
+ typedef typename Tree::Node Node;
+ struct Player {
+ Player(const Entry& entry, Node leaf): entry(entry), leaf(leaf) {}
+ Entry entry;
+ Node leaf;
+ };
+
+ void reallocate();
+
+#ifdef MATHIC_DEBUG
+ bool isValid() const;
+#endif
+
+ Tree _tree;
+ std::vector<Player> _players;
+ Configuration _conf;
+ };
+
+ template<class C>
+ void TourTree<C>::clear() {
+ _tree.clear();
+ _players.clear();
+ }
+
+ template<class C>
+ size_t TourTree<C>::getMemoryUse() const {
+ return _tree.getMemoryUse() +
+ _players.capacity() * sizeof(_players.front());
+ }
+
+ template<class C>
+ TourTree<C>::TourTree(const C& configuration): _conf(configuration) {
+ reallocate();
+ }
+
+ template<class C>
+ std::string TourTree<C>::getName() const {
+ return std::string("t-tree (") +
+ (C::fastIndex ? "fi" : "si") +
+ ')';
+ }
+
+ template<class C>
+ void TourTree<C>::push(Entry entry) {
+ MATHIC_ASSERT(isValid());
+ if (!_tree.hasFreeCapacity(2))
+ reallocate();
+ if (empty()) {
+ _players.push_back(Player(entry, Node()));
+ _tree.pushBackWithCapacity(&_players.back());
+ MATHIC_ASSERT(isValid());
+ return;
+ }
+ // move leaf down as left child
+ Node posParent = _tree.lastLeaf().next().parent();
+ Player* moveDown = _tree[posParent];
+ _tree.pushBackWithCapacity(moveDown);
+ moveDown->leaf = _tree.lastLeaf();
+ MATHIC_ASSERT(_tree.lastLeaf().isLeft());
+
+ // insert entry as right child
+ _players.push_back(Player(entry, _tree.lastLeaf().next()));
+ _tree.pushBackWithCapacity(&_players.back());
+ MATHIC_ASSERT(_tree.lastLeaf().isRight());
+
+ Node pos = _tree.lastLeaf();
+ do {
+ MATHIC_ASSERT(!pos.isRoot());
+ MATHIC_ASSERT(posParent == pos.parent());
+ typename C::CompareResult cmp = _conf.compare
+ (_tree[posParent]->entry, _tree[pos]->entry);
+ if (!_conf.cmpLessThan(cmp))
+ break;
+ _tree[posParent] = _tree[pos];
+ pos = posParent;
+ posParent = pos.parent();
+ } while (!pos.isRoot());
+ MATHIC_ASSERT(isValid());
+ }
+
+ template<class C>
+ template<class It>
+ void TourTree<C>::push(It begin, It end) {
+ for (; begin != end; ++begin)
+ push(*begin);
+ }
+
+ template<class C>
+ void TourTree<C>::decreaseTop(Entry newEntry) {
+ MATHIC_ASSERT(!empty());
+ Player* player = _tree[Node()];
+ player->entry = newEntry;
+ for (Node pos = player->leaf; !pos.isRoot(); pos = pos.parent()) {
+ Player* opponent = _tree[pos.sibling()];
+ if (_conf.cmpLessThan(_conf.compare(player->entry, opponent->entry)))
+ player = opponent;
+ _tree[pos.parent()] = player;
+ }
+ MATHIC_ASSERT(isValid());
+ }
+
+ template<class C>
+ typename TourTree<C>::Entry TourTree<C>::pop() {
+ MATHIC_ASSERT(!empty());
+ Entry top = _tree[Node()]->entry;
+ if (_tree.lastLeaf().isRoot()) {
+ _tree.popBack();
+ _players.pop_back();
+ MATHIC_ASSERT(isValid());
+ return top;
+ }
+ Node parentPos = _tree.lastLeaf().parent();
+ Player* left = _tree[_tree.lastLeaf().prev()];
+ Player* right = _tree[_tree.lastLeaf()];
+
+ if (right == _tree[parentPos]) {
+ // we want right to be the smaller entry so that it can be
+ // removed without that having an impact further up the tree.
+ std::swap(left->entry, right->entry);
+ for (Node pos = parentPos; _tree[pos] == right; pos = pos.parent()) {
+ _tree[pos] = left;
+ if (pos.isRoot())
+ break;
+ }
+ }
+ Player* player = _tree[Node()];
+ player->entry = right->entry; // let right take the winner's place
+ MATHIC_ASSERT(right == &_players.back());
+ _players.pop_back(); // remove right
+ left->leaf = parentPos; // move up left
+ _tree.popBack();
+ _tree.popBack();
+ for (Node pos = player->leaf; !pos.isRoot();) {
+ Player* opponent = _tree[pos.sibling()];
+ typename C::CompareResult cmp =
+ _conf.compare(player->entry, opponent->entry);
+ if (_conf.cmpLessThan(cmp))
+ player = opponent;
+ pos = pos.parent();
+ _tree[pos] = player;
+ }
+ MATHIC_ASSERT(isValid());
+ return top;
+ }
+
+ template<class C>
+ typename TourTree<C>::Entry TourTree<C>::top() const {
+ MATHIC_ASSERT(!empty());
+ return _tree[Node()]->entry;
+ }
+
+ template<class C>
+ void TourTree<C>::print(std::ostream& out) const {
+ out << getName() << ": {\n" << _tree << "}\n";
+ }
+
+ template<class C>
+ void TourTree<C>::reallocate() {
+ _tree.increaseCapacity();
+ const size_t newCapacity = _tree.capacity();
+ if (_players.empty())
+ _players.reserve(newCapacity / 2 + 2);
+ else {
+ Player* oldBegin = &_players.front();
+ _players.reserve(newCapacity / 2 + 2);
+ Player* newBegin = &_players.front();
+ for (Node pos; pos <= _tree.lastLeaf(); ++pos)
+ _tree[pos] = newBegin + (_tree[pos] - oldBegin);
+ }
+ MATHIC_ASSERT(isValid());
+ }
+
+#ifdef MATHIC_DEBUG
+ template<class C>
+ bool TourTree<C>::isValid() const {
+ MATHIC_ASSERT(_tree.capacity() + 1 <= 2 * _players.capacity());
+ MATHIC_ASSERT((empty() && _players.empty()) ||
+ (_tree.size() + 1 == 2 * _players.size()));
+ // _tree points into _players
+ for (Node pos; pos <= _tree.lastLeaf(); ++pos) {
+ size_t index = _tree[pos] - &(_players.front());
+ MATHIC_ASSERT(index < _players.size());
+ }
+
+ for (Node pos; pos <= _tree.lastLeaf(); ++pos) {
+ if (pos.left() >= _tree.lastLeaf()) { // leaf or two children
+ MATHIC_ASSERT(pos.right() > _tree.lastLeaf()); // pos is a leaf
+ MATHIC_ASSERT(_tree[pos]->leaf == pos);
+ } else {
+ MATHIC_ASSERT(pos.right() <= _tree.lastLeaf()); // pos has two children
+ // exactly one child wins
+ MATHIC_ASSERT(_tree[pos.left()] != _tree[pos.right()]);
+ MATHIC_ASSERT(_tree[pos] == _tree[pos.left()] ||
+ _tree[pos] == _tree[pos.right()]);
+ MATHIC_ASSERT(!_conf.cmpLessThan(
+ _conf.compare(_tree[pos]->entry, _tree[pos.left()]->entry)));
+ MATHIC_ASSERT(!_conf.cmpLessThan(
+ _conf.compare(_tree[pos]->entry, _tree[pos.right()]->entry)));
+ }
+ }
+ return true;
+ }
+#endif
+}
+
+#endif
diff --git a/src/mathic/display.cpp b/src/mathic/display.cpp
new file mode 100755
index 0000000..a149a40
--- /dev/null
+++ b/src/mathic/display.cpp
@@ -0,0 +1,145 @@
+#include "display.h"
+
+#include <cctype>
+#include <cstdio>
+
+namespace mathic {
+ namespace {
+ /** Automatically break lines at this width. */
+ static const size_t ConsoleWidth = 79;
+
+ /** Helper class for display(). */
+ class Printer {
+ public:
+ Printer(const std::string& msg, const std::string& prepend):
+ _pos(0), _lineSize(0), _msg(msg), _prefix(prepend) {
+
+ std::string wordSpacePrefix;
+
+ while (_pos < _msg.size()) {
+ // We are always at the start of a line at this point.
+ MATHIC_ASSERT(_lineSize == 0);
+ readIndentation();
+ printRaw(_prefix);
+ printRaw(_indentation);
+
+ if (_pos == _msg.size())
+ break;
+ if (_msg[_pos] == '\n') {
+ newLine();
+ ++_pos;
+ continue;
+ }
+
+ wordSpacePrefix.clear();
+ while (_pos < _msg.size()) {
+ if (_msg[_pos] == '\n') {
+ ++_pos;
+ break;
+ }
+ if (isspace(_msg[_pos])) {
+ wordSpacePrefix += _msg[_pos];
+ ++_pos;
+ continue;
+ }
+ MATHIC_ASSERT(!isspace(_msg[_pos]));
+ MATHIC_ASSERT(_msg[_pos] != '\n');
+ MATHIC_ASSERT(_pos < _msg.size());
+
+ std::string word;
+ while (_pos < _msg.size() &&
+ _msg[_pos] != '\n' &&
+ !isspace(_msg[_pos])) {
+ word += _msg[_pos];
+ ++_pos;
+ }
+ MATHIC_ASSERT(!word.empty());
+ printWord(wordSpacePrefix, word);
+ wordSpacePrefix.clear();
+ }
+
+ newLine();
+ }
+ }
+
+ private:
+ void newLine() {
+ printRaw('\n');
+ _lineSize = 0;
+ }
+
+ void readIndentation() {
+ // Read whitespace at beginning of line.
+ _indentation.clear();
+ while (_pos < _msg.size() && _msg[_pos] != '\n' && isspace(_msg[_pos])) {
+ _indentation += _msg[_pos];
+ ++_pos;
+ }
+ }
+
+ void printWord(const std::string& wordSpacePrefix, const std::string& word) {
+ MATHIC_ASSERT(!word.empty());
+
+ // Note that this will print beyond the console width if word is
+ // the first thing we are printing on this line. That is because
+ // there then is no way to fit the word on one line.
+ size_t wordAndPrefixSize = word.size() + wordSpacePrefix.size();
+ if (_lineSize != 0 && _lineSize + wordAndPrefixSize > ConsoleWidth) {
+ // we skip space before word if inserting newline
+ newLine();
+ printRaw(_prefix);
+ printRaw(_indentation);
+ } else
+ printRaw(wordSpacePrefix);
+ printRaw(word);
+ }
+
+ void printRaw(const std::string& word) {
+ fputs(word.c_str(), stderr);
+ _lineSize += word.size();
+ }
+
+ void printRaw(char c) {
+ fputc(c, stderr);
+ ++_lineSize;
+ }
+
+ size_t _pos;
+ size_t _lineSize;
+ const std::string& _msg;
+ const std::string& _prefix;
+ std::string _indentation;
+ };
+ }
+
+ void display(const std::string& msg, const std::string& prepend) {
+ Printer(msg, prepend);
+ }
+
+ void displayNote(const std::string& msg) {
+ display("NOTE: " + msg + "\n");
+ }
+
+ void displayError(const std::string& msg) {
+ display("ERROR: " + msg + "\n");
+ }
+
+ void displayInternalError(const std::string& msg) {
+ display("INTERNAL ERROR: " + msg + "\n");
+ }
+
+ void displayException(const std::exception& exception) {
+ try {
+ display(exception.what());
+ } catch (...) {
+ fputs("\n\n*** Error while printing error! ***\n", stderr);
+ fflush(stderr);
+ fputs("*** Retrying display of error using simpler display method. ***\n",
+ stderr);
+ fflush(stderr);
+ fputs(exception.what(), stderr);
+ fflush(stderr);
+ throw;
+ }
+ }
+}
diff --git a/src/mathic/display.h b/src/mathic/display.h
new file mode 100755
index 0000000..f086f4a
--- /dev/null
+++ b/src/mathic/display.h
@@ -0,0 +1,41 @@
+#ifndef MATHIC_DISPLAY_GUARD
+#define MATHIC_DISPLAY_GUARD
+
+#include <string>
+#include "stdinc.h"
+
+/** @file display.h
+
+ This file contains functions for printing strings to standard
+ error. They all perform automatic line breaking suitable for printing
+ to a console.
+*/
+
+namespace mathic {
+ /** Display msg to standard error with automatic line breaking. If a
+ automatically broken line begins with whitespace, that whitespace is
+ repeated in front of every line that is generated from breaking
+ it.
+
+ @param prepend Print this in front of every line that is printed.
+ */
+ void display(const std::string& msg, const std::string& prepend = "");
+
+ /** Display msg to standard error in a way that indicates that this is
+ something that the user should take note of but that is not an
+ error. */
+ void displayNote(const std::string& msg);
+
+ /** Display msg to standard error in a way that indicates that it is
+ an error. */
+ void displayError(const std::string& msg);
+
+ /** Display msg to standard in a way that indicates that it is an
+ internal error. */
+ void displayInternalError(const std::string& errorMsg);
+
+ /** Display the message of exception. */
+ void displayException(const std::exception& exception);
+}
+
+#endif
diff --git a/src/mathic/error.cpp b/src/mathic/error.cpp
new file mode 100755
index 0000000..3f388a8
--- /dev/null
+++ b/src/mathic/error.cpp
@@ -0,0 +1,22 @@
+#include "error.h"
+#include <sstream>
+
+namespace mathic {
+ void reportError(const std::string& errorMsg) {
+ throw MathicException("ERROR: " + errorMsg);
+ }
+
+ void reportInternalError(const std::string& errorMsg) {
+ throw InternalMathicException("INTERNAL ERROR: " + errorMsg);
+ }
+
+ void reportInternalError
+ (const std::string& errorMsg, const char* file, unsigned int lineNumber) {
+
+ std::ostringstream err;
+ err << errorMsg << '\n'
+ << "The internal error occured in file " << file
+ << " on line " << lineNumber << '.';
+ reportInternalError(err.str());
+ }
+}
diff --git a/src/mathic/error.h b/src/mathic/error.h
new file mode 100755
index 0000000..6c9353b
--- /dev/null
+++ b/src/mathic/error.h
@@ -0,0 +1,56 @@
+#ifndef MATHIC_ERROR_GUARD
+#define MATHIC_ERROR_GUARD
+
+#include <stdexcept>
+#include <string>
+
+namespace mathic {
+ /** This is the base of the Mathic exception hierarchy for exceptions
+ that can occur due to expected error conditions. */
+ class MathicException : public std::runtime_error {
+ public:
+ MathicException(const std::string& str): runtime_error(str) {}
+ };
+
+ /** This exception signals that a bug in Mathic has been detected. */
+ class InternalMathicException : public std::logic_error {
+ public:
+ InternalMathicException(const std::string& str): logic_error(str) {}
+ };
+
+ // The do {...} while (0) is to collect everything into a single
+ // statement that still requires a semicolon after it. The throw is to
+ // prevent spurious compiler warnings about a missing return
+ // statement.
+ #define MATHIC_INTERNAL_ERROR(msg) \
+ do { \
+ reportInternalError(msg, __FILE__, __LINE__); \
+ throw; \
+ } while (false)
+ #define INTERNAL_ERROR_UNIMPLEMENTED() \
+ INTERNAL_ERROR("Called function that has not been implemented.")
+
+ // These methods throw exceptions.
+ void reportError(const std::string& errorMsg);
+ void reportInternalError(const std::string& errorMsg);
+ void reportInternalError
+ (const std::string& errorMsg, const char* file, unsigned int lineNumber);
+
+ template<class Exception>
+ void throwError(const std::string& errorMsg) {
+ throw Exception("ERROR: " + errorMsg + '\n');
+ }
+
+
+ #define MATHIC_DEFINE_EXCEPTION(NAME) \
+ class NAME##Exception : public MathicException { \
+ public: \
+ NAME##Exception(const std::string& str): MathicException(str) {} \
+ }
+
+ MATHIC_DEFINE_EXCEPTION(UnknownName);
+ MATHIC_DEFINE_EXCEPTION(AmbiguousName);
+ MATHIC_DEFINE_EXCEPTION(Unsupported);
+}
+
+#endif
diff --git a/src/mathic/main.cpp b/src/mathic/main.cpp
new file mode 100755
index 0000000..dce1663
--- /dev/null
+++ b/src/mathic/main.cpp
@@ -0,0 +1,17 @@
+#include "divsim/divMain.h"
+#include "pqsim/pqMain.h"
+#include <string>
+#include <iostream>
+
+int main(int argc, const char** args) {
+ std::string name = args[0];
+ const size_t offset = name.find_last_of("/\\");
+ if (offset != std::string::npos)
+ name = name.substr(offset + 1);
+ if (name == "div")
+ return divMain();
+ else if (name == "pq")
+ return pqMain(argc, args);
+ std::cout << "Name of executable must be div or pq.\n";
+ return 1;
+}
diff --git a/src/mathic/stdinc.h b/src/mathic/stdinc.h
new file mode 100755
index 0000000..3311b15
--- /dev/null
+++ b/src/mathic/stdinc.h
@@ -0,0 +1,26 @@
+#ifndef MATHIC_STDINC_GUARD
+#define MATHIC_STDINC_GUARD
+
+#if (defined DEBUG || defined _DEBUG) && (!(defined MATCHIC_NDEBUG))
+#ifndef MATHIC_DEBUG
+#define MATHIC_DEBUG
+#endif
+#include <cassert>
+#define MATHIC_ASSERT(X) assert(X)
+#endif
+
+#ifndef MATHIC_ASSERT
+#define MATHIC_ASSERT(X)
+#endif
+
+namespace mathic {
+ static const unsigned long BitsPerByte = 8;
+}
+
+#ifndef MATHIC_NO_MIC_NAMESPACE
+namespace mic {
+ using namespace mathic;
+}
+#endif
+
+#endif
diff --git a/src/pqsim/GeobucketModel.h b/src/pqsim/GeobucketModel.h
new file mode 100755
index 0000000..fef45f7
--- /dev/null
+++ b/src/pqsim/GeobucketModel.h
@@ -0,0 +1,68 @@
+#ifndef GEOBUCKET_MODEL_GUARD
+#define GEOBUCKET_MODEL_GUARD
+
+#include "Model.h"
+#include "mathic/Geobucket.h"
+
+template<
+ bool TrackFront,
+ bool MinBucketBinarySearch,
+ bool Premerge,
+ bool CollectMax,
+ int BucketStorage,
+ size_t InsertFactor>
+class GeobucketModelBase {
+public:
+ GeobucketModelBase(size_t geoBase, size_t minBucketSize):
+ geoBase(geoBase), minBucketSize(minBucketSize) {}
+ size_t geoBase;
+ size_t minBucketSize;
+
+ static const bool trackFront = TrackFront;
+ static const bool minBucketBinarySearch = MinBucketBinarySearch;
+ static const bool premerge = Premerge;
+ static const bool collectMax = CollectMax;
+ static const mathic::GeobucketBucketStorage bucketStorage =
+ (mathic::GeobucketBucketStorage)BucketStorage;
+ static const size_t insertFactor = InsertFactor;
+};
+
+template<
+ bool OnSpans,
+ bool TrackFront,
+ bool MinBucketBinarySearch,
+ bool Deduplicate,
+ bool Premerge,
+ bool CollectMax,
+ int BucketStorage,
+ size_t InsertFactor = 1>
+class GeobucketModel :
+ public Model<
+ OnSpans,
+ Deduplicate,
+ false,
+ mathic::Geobucket,
+ GeobucketModelBase<
+ TrackFront,
+ MinBucketBinarySearch,
+ Premerge,
+ CollectMax,
+ BucketStorage,
+ InsertFactor> > {
+public:
+ GeobucketModel(size_t geoBase, size_t minBucketSize):
+ Model<
+ OnSpans,
+ Deduplicate,
+ false,
+ mathic::Geobucket,
+ GeobucketModelBase<
+ TrackFront,
+ MinBucketBinarySearch,
+ Premerge,
+ CollectMax,
+ BucketStorage,
+ InsertFactor> >(geoBase, minBucketSize) {}
+};
+
+#endif
diff --git a/src/pqsim/HeapModel.h b/src/pqsim/HeapModel.h
new file mode 100755
index 0000000..ad39299
--- /dev/null
+++ b/src/pqsim/HeapModel.h
@@ -0,0 +1,16 @@
+#ifndef HEAP_MODEL_GUARD
+#define HEAP_MODEL_GUARD
+
+#include "Model.h"
+#include "mathic/Heap.h"
+
+template<bool FastIndex>
+struct HeapModelBase {
+ static const bool fastIndex = FastIndex;
+};
+
+template<bool OnSpans, bool Deduplicate, bool FastIndex>
+class HeapModel : public Model<
+ OnSpans, Deduplicate, true, mathic::Heap, HeapModelBase<FastIndex> > {};
+
+#endif
diff --git a/src/pqsim/Item.cpp b/src/pqsim/Item.cpp
new file mode 100755
index 0000000..3ab11f3
--- /dev/null
+++ b/src/pqsim/Item.cpp
@@ -0,0 +1,9 @@
+#include "stdinc.h"
+#include "Item.h"
+
+void Item::print(std::ostream& out) const {
+ if (atEnd())
+ out << "invalid";
+ else
+ out << getValue();
+}
diff --git a/src/pqsim/Item.h b/src/pqsim/Item.h
new file mode 100755
index 0000000..1792ad7
--- /dev/null
+++ b/src/pqsim/Item.h
@@ -0,0 +1,110 @@
+#ifndef ITEM_GUARD
+#define ITEM_GUARD
+
+#include <ostream>
+#include <vector>
+
+typedef unsigned long Value;
+
+class Item;
+enum CompareResult {Less, Equal, Greater};
+CompareResult compare(Value a, Value b);
+CompareResult compare(const Item& a, const Item& b);
+
+class Item {
+ public:
+ Item(); // creates Item which is at end.
+ explicit Item(Value value);
+ Item(const Value* begin, const Value* end);
+
+ bool atEnd() const;
+ void toNext();
+ Item getNext() const;
+ size_t getLength() const;
+
+ const Value* begin() const {return _current;}
+ const Value* end() const {return _end;}
+
+ Value getValue() const;
+
+ void print(std::ostream& out) const;
+
+ bool operator==(const Item& item);
+
+ private:
+ Value _value;
+ const Value* _current;
+ const Value* _end;
+ Value dummy; // to make sizeof(Item) a power of two
+};
+
+template<bool> struct ItemOrValue{};
+template<> struct ItemOrValue<true> {typedef Item Entry;};
+template<> struct ItemOrValue<false> {typedef Value Entry;};
+
+inline CompareResult compare(Value a, Value b) {
+ if (a < b)
+ return Less;
+ if (b < a)
+ return Greater;
+ return Equal;
+}
+
+inline CompareResult compare(const Item& a, const Item& b) {
+ if (a.getValue() < b.getValue())
+ return Less;
+ if (b.getValue() < a.getValue())
+ return Greater;
+ return Equal;
+}
+
+
+inline std::ostream& operator<<(std::ostream& out, const Item& item) {
+ item.print(out);
+ return out;
+}
+
+inline bool Item::atEnd() const {
+ return _current == _end;
+}
+
+inline Value Item::getValue() const {
+ ASSERT(!atEnd());
+ return _value;
+}
+
+inline void Item::toNext() {
+ ASSERT(!atEnd());
+ ++_current;
+ if (!atEnd()) {
+ ASSERT(_value >= *_current);
+ _value = *_current;
+ }
+}
+
+inline Item Item::getNext() const {
+ ASSERT(!atEnd());
+ Item next(*this);
+ next.toNext();
+ return next;
+}
+
+inline bool Item::operator==(const Item& item) {
+ return getValue() == item.getValue();
+}
+
+inline Item::Item(): _value(-1), _current(0), _end(0) {}
+
+inline Item::Item(Value value): _value(value), _current(0), _end(0) {
+ ++_end;
+}
+
+inline Item::Item(const Value* begin, const Value* end):
+ _value(begin != end ? *begin : 0), _current(begin), _end(end) {}
+
+inline size_t Item::getLength() const {
+ return _end - _current;
+}
+
+
+#endif
diff --git a/src/pqsim/Model.cpp b/src/pqsim/Model.cpp
new file mode 100644
index 0000000..f9d51f0
--- /dev/null
+++ b/src/pqsim/Model.cpp
@@ -0,0 +1,2 @@
+#include "stdinc.h"
+#include "Model.h"
diff --git a/src/pqsim/Model.h b/src/pqsim/Model.h
new file mode 100644
index 0000000..12767d5
--- /dev/null
+++ b/src/pqsim/Model.h
@@ -0,0 +1,202 @@
+#ifndef MODEL_GUARD
+#define MODEL_GUARD
+
+#include "Item.h"
+#include <vector>
+
+namespace ModelHelper {
+ class NullConfigurationBase {};
+ template<bool> struct OnSpans {};
+ template<bool> struct UseDecreaseTop {};
+
+ template<class DS>
+ inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<0>);
+ template<class DS>
+ inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<1>);
+ template<class DS, bool DT>
+ inline Value pop(DS& ds, OnSpans<0>, UseDecreaseTop<DT>);
+
+ template<class DS>
+ inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<0>);
+ template<class DS>
+ inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<1>);
+
+ inline Value deduplicate
+ (std::vector<Value>& pending, const Value& a, const Value& b);
+ inline Item deduplicate
+ (std::vector<Item>& pending, const Item& a, const Item& b);
+}
+
+template<
+ bool OnSpans,
+ bool Deduplicate,
+ bool UseDecreaseTop,
+ template<class> class DataStructure,
+ class ConfigurationBase = ModelHelper::NullConfigurationBase>
+class Model {
+public:
+ Model(): _ds(Configuration()) {}
+ template<class A>
+ Model(const A& a): _ds(Configuration(a)) {}
+ template<class A, class B>
+ Model(const A& a, const B& b): _ds(Configuration(a, b)) {}
+
+ std::string getName() const {
+ return _ds.getName() +
+ (UseDecreaseTop ? " dectop" : "") +
+ (OnSpans ? " on spans" : " on elements");
+ }
+
+ void push(const Value* begin, const Value* end) {
+ ModelHelper::push(_ds, begin, end, ModelHelper::OnSpans<OnSpans>());
+ }
+
+ Value pop() {
+ return ModelHelper::pop(_ds,
+ ModelHelper::OnSpans<OnSpans>(),
+ ModelHelper::UseDecreaseTop<UseDecreaseTop>());
+ }
+
+ bool empty() const {return _ds.empty();}
+ void print(std::ostream& out) const {_ds.print(out);}
+
+ size_t getComparisons() const {
+ return _ds.getConfiguration().getComparisons();
+ }
+
+ size_t getMemoryUse() const {
+ return _ds.getMemoryUse();
+ }
+
+private:
+ class Configuration : public ConfigurationBase {
+ public:
+ typedef typename ItemOrValue<OnSpans>::Entry Entry;
+
+ Configuration(): _comparisons(0) {}
+ template<class A, class B>
+ Configuration(const A& a, const B& b):
+ ConfigurationBase(a, b), _comparisons(0) {}
+
+ typedef ::CompareResult CompareResult;
+ CompareResult compare(const Entry& a, const Entry& b) const {
+ ++_comparisons;
+ return ::compare(a, b);
+ }
+ bool cmpLessThan(CompareResult r) const {return r == Less;}
+ bool cmpEqual(CompareResult r) const {
+ ASSERT(supportDeduplication);
+ return r == Equal;
+ }
+ Entry deduplicate(const Entry& a, const Entry& b) const {
+ ASSERT(supportDeduplication);
+ return ModelHelper::deduplicate(_pending, a, b);
+ }
+
+ std::vector<Entry>& getPending() {return _pending;}
+ size_t getComparisons() const {return _comparisons;}
+
+ static const bool supportDeduplication = Deduplicate;
+
+ private:
+ mutable size_t _comparisons;
+ mutable std::vector<Entry> _pending;
+ };
+
+ DataStructure<Configuration> _ds;
+};
+
+namespace ModelHelper {
+ template<class DS>
+ inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<0>) {
+ ds.push(begin, end);
+ }
+ template<class DS>
+ inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<1>) {
+ ds.push(Item(begin, end));
+ }
+
+ template<class DS, bool DT>
+ inline Value pop(DS& ds, OnSpans<0>, UseDecreaseTop<DT>) {
+ Value topValue = ds.top();
+ do {
+ ds.pop();
+ } while (!ds.empty() && ds.top() == topValue);
+ return topValue;
+ }
+
+ template<class DS>
+ inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<0>) {
+ ASSERT(DS::Configuration::supportDeduplication ||
+ ds.getConfiguration().getPending().empty());
+ Value topValue = ds.top().getValue();
+ do {
+ Item top = ds.pop();
+ top.toNext();
+ if (!top.atEnd())
+ ds.push(top);
+
+ if (DS::Configuration::supportDeduplication) {
+ std::vector<Item>& pending = ds.getConfiguration().getPending();
+ while (!pending.empty()) {
+ // this has to work even if push changes pending, which is
+ // why the loop is done like this.
+ Item item = pending.back();
+ pending.pop_back();
+ ds.push(item);
+ }
+ } else {
+ ASSERT(ds.getConfiguration().getPending().empty());
+ }
+ } while (!ds.empty() && ds.top().getValue() == topValue);
+ ASSERT(DS::Configuration::supportDeduplication ||
+ ds.getConfiguration().getPending().empty());
+ return topValue;
+ }
+
+ template<class DS>
+ inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<1>) {
+ ASSERT(DS::Configuration::supportDeduplication ||
+ ds.getConfiguration().getPending().empty());
+ Value topValue = ds.top().getValue();
+ do {
+ Item top = ds.top();
+ top.toNext();
+ if (!top.atEnd())
+ ds.decreaseTop(top);
+ else
+ ds.pop();
+
+ ASSERT(DS::Configuration::supportDeduplication ||
+ ds.getConfiguration().getPending().empty());
+ if (DS::Configuration::supportDeduplication) {
+ std::vector<Item>& pending = ds.getConfiguration().getPending();
+ while (!pending.empty()) {
+ // this has to work even if push changes pending, which is
+ // why the loop is done like this.
+ Item item = pending.back();
+ pending.pop_back();
+ ds.push(item);
+ }
+ }
+ } while (!ds.empty() && ds.top().getValue() == topValue);
+ ASSERT(DS::Configuration::supportDeduplication ||
+ ds.getConfiguration().getPending().empty());
+ return topValue;
+ }
+
+ inline Value deduplicate
+ (std::vector<Value>& pending, const Value& a, const Value& b) {
+ return a;
+ }
+ inline Item deduplicate
+ (std::vector<Item>& pending, const Item& a, const Item& b) {
+ Item next = b;
+ next.toNext();
+ if (!next.atEnd())
+ pending.push_back(next);
+ return a;
+ }
+}
+
+#endif
diff --git a/src/pqsim/Simulator.cpp b/src/pqsim/Simulator.cpp
new file mode 100755
index 0000000..8ff8c10
--- /dev/null
+++ b/src/pqsim/Simulator.cpp
@@ -0,0 +1,326 @@
+#include "stdinc.h"
+#include "Simulator.h"
+
+#include "mathic/ColumnPrinter.h"
+#include <queue>
+#include <iterator>
+#include <algorithm>
+#include <set>
+
+namespace {
+ std::string commafy(unsigned long l) {
+ std::stringstream out;
+ out << l;
+ std::string str;
+ for (size_t i = 0; i < out.str().size(); ++i) {
+ str += out.str()[i];
+ if (i != out.str().size() - 1 && ((out.str().size() - i) % 3) == 1)
+ str += ',';
+ }
+ return str;
+ }
+
+ struct SimBuilder {
+ typedef Simulator::Event Event;
+ SimBuilder(bool popDuplicates,
+ std::vector<Value>& mem,
+ std::vector<Event>& events):
+ _popDuplicates(popDuplicates),
+ _mem(mem),
+ _events(events),
+ _pushCount(0),
+ _popCount(0),
+ _liveCountSum(0),
+ _pushSum(0),
+ _duplicateCount(0) {
+ _events.clear();
+ _mem.clear();
+ }
+
+ size_t getLiveCount() const {return _queue.size();}
+ size_t getPushCount() const {return _pushCount;}
+ size_t getPushSum() const {return _pushSum;}
+ size_t getPopCount() const {return _popCount;}
+ size_t getAvgLiveCount() const {
+ return _events.empty() ? 0 : _liveCountSum / _events.size();
+ }
+ size_t getDupliateCount() const {return _duplicateCount;}
+
+ // call nothing but addToPush and isInPush
+ // after calling beginPush until you call endPush.
+ void beginPush() {
+ ASSERT(_push.empty());
+ _liveCountSum += getLiveCount();
+ _events.push_back(Event());
+ _events.back().begin = _mem.size();
+ }
+ void addToPush(Value v) {
+ if (isLive(v))
+ ++_duplicateCount;
+ _push.insert(v); // for faster isInPush
+ _mem.push_back(v);
+ _queue.insert(v);
+ }
+ bool isInPush(Value v) {
+ return _push.find(v) != _push.end();
+ }
+ void endPush() {
+ Event& e = _events.back();
+ e.size = _mem.size() - e.begin;
+ std::vector<Value>::iterator begin = _mem.begin() + e.begin;
+ std::sort(begin, begin + e.size, std::greater<Value>());
+ ++_pushCount;
+ _pushSum += e.size;
+ _push.clear();
+ }
+
+ // todo: move clients to use begin...endpush
+ template<class It>
+ void push(It begin, It end) {
+ beginPush();
+ for (It it = begin; it != end; ++it)
+ addToPush(*it);
+ endPush();
+ }
+
+ Value pop() {
+ _liveCountSum += getLiveCount();
+ ++_popCount;
+ Value top = *_queue.rbegin();
+ do {
+ std::multiset<Value>::iterator last = _queue.end();
+ --last;
+ _queue.erase(last);
+ } while (_popDuplicates && !_queue.empty() && *_queue.rbegin() == top);
+ Event e;
+ e.popValue = top;
+ _events.push_back(e);
+ return top;
+ }
+
+ bool noLive() const {return _queue.empty();}
+
+ Value getRandomLive() const {
+ ASSERT(!noLive());
+ const size_t randomIndex = rand() % _queue.size();
+ std::multiset<Value>::const_iterator it = _queue.begin();
+ std::advance(it, randomIndex);
+ return *it;
+ }
+
+ bool isLive(Value v) const {
+ return _queue.find(v) != _queue.end();
+ }
+
+ private:
+ bool _popDuplicates;
+ std::multiset<Value> _queue;
+ std::multiset<Value> _push;
+ std::vector<Value>& _mem;
+ std::vector<Event>& _events;
+ size_t _pushCount;
+ size_t _popCount;
+ size_t _liveCountSum;
+ size_t _pushSum;
+ size_t _duplicateCount;
+ };
+
+ std::string makeDescription(SimBuilder& sim, size_t repeats,
+ std::string name) {
+ std::ostringstream out;
+ const size_t traffic = sim.getPushSum();
+ out << "*** Simulation \"" << name << "\"\n ";
+ out << sim.getPushCount() << " spans\n ";
+ out << (traffic / sim.getPushCount()) << " per span on average\n ";
+ out << sim.getAvgLiveCount() << " elements in queue on average\n ";
+ out << traffic << " entries popped in total.\n ";
+ out << (sim.getDupliateCount() * 100 / traffic) << "% duplicates\n ";
+ out << repeats << " repeats.\n";
+ return out.str();
+ }
+}
+
+void Simulator::dupSpans
+ (size_t pushSumGoal, size_t avgSpan, size_t avgLiveGoal,
+ size_t dupPercentage) {
+ SimBuilder sim(true, _mem, _events);
+ //size_t liveDeviation = 30;
+ size_t spanDeviation = 10;
+ ASSERT(avgSpan > 0);
+ if (avgSpan <= spanDeviation)
+ spanDeviation = avgSpan - 1;
+
+ while (sim.getPushSum() < pushSumGoal || !sim.noLive()) {
+ bool doPush = (sim.getAvgLiveCount() < avgLiveGoal);
+ if (sim.getPushSum() == pushSumGoal)
+ doPush = false;
+ else if (sim.noLive())
+ doPush = true;
+
+ if (doPush) {
+ const size_t size =
+ avgSpan - spanDeviation + rand() % (2 * spanDeviation);
+ sim.beginPush();
+ for (size_t i = 0; i < size; ++i) {
+ if (!sim.noLive() &&
+ static_cast<size_t>(rand() % 100) <= dupPercentage) {
+ Value v;
+ size_t tries = 0;
+ // if there are only fewer elements to duplicate than there
+ // are elements in the push, then this will never succeed.
+ // It will also take a long time to succeed even in some situations
+ // where it is possible. So we only try it for so long.
+ do {
+ v = (tries < 20 ? sim.getRandomLive() : rand());
+ ++tries;
+ } while (sim.isInPush(v));
+ sim.addToPush(v);
+ } else {
+ Value v;
+ do {
+ v = rand();
+ } while (sim.isInPush(v) || sim.isLive(v));
+ sim.addToPush(v);
+ }
+ }
+ sim.endPush();
+ } else
+ sim.pop();
+ }
+ _description = makeDescription(sim, _repeats, "dup spans");
+}
+
+void Simulator::orderSpans
+(size_t spanCount, size_t spanSize, size_t avgSize) {
+ SimBuilder sim(true, _mem, _events);
+ size_t insNum = (spanSize + spanCount * avgSize) * 3;
+ size_t deviation = (spanSize) / 2;
+ if (deviation == 0)
+ deviation = 1;
+ if (deviation > avgSize)
+ deviation = avgSize - 1;
+
+ while (sim.getLiveCount() > 0 || sim.getPushCount() < spanCount) {
+ const size_t live = sim.getLiveCount();
+ const size_t minLive = avgSize - deviation;
+ const size_t pushes = sim.getPushCount();
+ if (live == 0 || (pushes < spanCount && live < minLive)) {
+ sim.beginPush();
+ for (size_t i = 0; i < spanSize; ++i) {
+ Value v;
+ do {
+ v = insNum + rand() % (2*avgSize);
+ } while (sim.isInPush(v));
+ --insNum;
+ sim.addToPush(v);
+ }
+ sim.endPush();
+ } else
+ sim.pop();
+ }
+
+ _description = makeDescription(sim, _repeats, "ordered spans");
+}
+
+void Simulator::randomSpans(size_t spanCount, size_t spanSize, size_t initialSize) {
+ SimBuilder sim(false, _mem, _events);
+ while (sim.getLiveCount() || sim.getPushCount() < spanCount) {
+ bool doPop = rand() % (spanSize + 1) != 0;
+ if (sim.getLiveCount() == 0)
+ doPop = false;
+ if (sim.getPushCount() == spanCount)
+ doPop = true;
+
+ if (doPop)
+ sim.pop();
+ else {
+ size_t size = (sim.getPushCount() == 0 ? initialSize : spanSize);
+ sim.beginPush();
+ for (size_t i = 0; i < size; ++i) {
+ Value v;
+ do {
+ v = rand();
+ } while (sim.isInPush(v));
+ sim.addToPush(v);
+ }
+ sim.endPush();
+ }
+ }
+ _description = makeDescription(sim, _repeats, "random spans");
+}
+
+void Simulator::printEventSummary(std::ostream& out) const {
+ out << _description << std::endl;
+}
+
+void Simulator::printEvents(std::ostream& out) const {
+ out << "*** The " << _events.size() << " events are\n";
+ for (size_t i = 0; i < _events.size(); ++i)
+ print(_events[i], out);
+}
+
+void Simulator::print(const Event& e, std::ostream& out) const {
+ if (e.size == 0)
+ out << "Pop " << e.popValue << '\n';
+ else {
+ out << "Insert";
+ std::vector<Value>::const_iterator it = _mem.begin() + e.begin;
+ std::vector<Value>::const_iterator end = it + e.size;
+ for (; it != end; ++it)
+ out << ' ' << *it;
+ out << '\n';
+ }
+}
+
+void Simulator::printData(std::ostream& out) const {
+ std::vector<SimData> sorted(_data);
+ sort(sorted.begin(), sorted.end());
+ out << "*** Simulation outcome ***" << std::endl;
+ mic::ColumnPrinter pr;
+ pr.addColumn(true);
+ pr.addColumn(false, " ", "ms");
+ pr.addColumn(false, " ", "cmps");
+ pr.addColumn(false, " ", "kb");
+ for (std::vector<SimData>::const_iterator it = sorted.begin();
+ it != sorted.end(); ++it) {
+ pr[0] << it->name << '\n';
+ pr[1] << commafy(it->mseconds) << '\n';
+ pr[2] << commafy(it->comparisons) << '\n';
+ pr[3] << commafy(it->memoryUse / 1024) << '\n';
+ }
+ pr.print(out);
+}
+
+void Simulator::setupEvents() {
+ size_t activeSum = 0;
+ std::priority_queue<int> queue;
+ typedef std::vector<Event>::iterator Iterator;
+ Iterator end = _events.end();
+ for (Iterator it = _events.begin(); it != end; ++it) {
+ Event& e = *it;
+ activeSum += queue.size();
+ if (e.size == 0) {
+ e.popValue = queue.top();
+ queue.pop();
+ } else {
+ Value* begin = &(_mem[e.begin]);
+ Value* end = begin + e.size;
+ sort(begin, end, std::greater<Value>());
+ for (const Value* v = begin; v != end; ++v)
+ queue.push(*v);
+ }
+ }
+ _avgSize = activeSum / _events.size();
+}
+
+void Simulator::SimData::print(std::ostream& out) {
+ out << name
+ << " " << commafy(mseconds) << " ms"
+ << " " << commafy(comparisons) << " cmps"
+ << " " << commafy(memoryUse / 1024) << " kb"
+ << '\n';
+}
+
+bool Simulator::SimData::operator<(const SimData& sd) const {
+ return mseconds < sd.mseconds;
+}
diff --git a/src/pqsim/Simulator.h b/src/pqsim/Simulator.h
new file mode 100755
index 0000000..e11a610
--- /dev/null
+++ b/src/pqsim/Simulator.h
@@ -0,0 +1,103 @@
+#ifndef SIMULATOR_GUARD
+#define SIMULATOR_GUARD
+
+#include "Item.h"
+#include <queue>
+#include <vector>
+#include <ctime>
+#include <algorithm>
+#include <sstream>
+#include <iostream>
+#include <string>
+
+class Simulator {
+public:
+ Simulator(size_t repeats): _repeats(repeats), _simType("none") {}
+
+ void dupSpans(size_t pushSumGoal, size_t avgSpan, size_t avgLiveGoal,
+ size_t dupPercentage);
+ void orderSpans(size_t spanCount, size_t spanSize, size_t avgSize);
+ void randomSpans(size_t spanCount, size_t spanSize, size_t initialSize);
+
+ template<class PQueue>
+ void run(PQueue& pq, bool printData = true, bool printStates = false);
+
+ void printEventSummary(std::ostream& out) const;
+ void printEvents(std::ostream& out) const;
+ void printData(std::ostream& out) const;
+
+ struct Event {
+ Event(): size(0) {}
+ size_t begin;
+ size_t size; // insert _mem( [begin, begin + size) ) if size > 0.
+ Value popValue; // pop this value if size == 0
+ };
+
+private:
+ struct SimData {
+ std::string name;
+ unsigned long comparisons;
+ unsigned long mseconds;
+ size_t memoryUse;
+ bool operator<(const SimData& sd) const;
+ void print(std::ostream& out);
+ };
+
+ void setupEvents();
+ void print(const Event& e, std::ostream& out) const;
+
+ std::vector<Event> _events;
+ std::vector<SimData> _data;
+ std::vector<Value> _mem;
+ size_t _spanCount;
+ size_t _spanSize;
+ size_t _avgSize;
+ size_t _repeats;
+ std::string _simType;
+ std::string _description;
+};
+
+template<class PQueue>
+void Simulator::run(PQueue& pqueue, bool printData, bool printStates) {
+ clock_t timeBegin = clock();
+ std::vector<Event>::const_iterator end = _events.end();
+ for (size_t turn = 0; turn < _repeats; ++turn) {
+ typedef std::vector<Event>::const_iterator CIterator;
+ CIterator end = _events.end();
+ for (CIterator it = _events.begin(); it != end; ++it) {
+ const Event& e = *it;
+ if (printStates) {
+ std::cerr << "*** The next event is\n";
+ print(e, std::cerr);
+ std::cerr << "*** The state of " << pqueue.getName()
+ << " (" << pqueue.getComparisons() << " comparisons) is\n";
+ pqueue.print(std::cerr);
+ std::cerr << '\n';
+ }
+ if (e.size == 0) {
+ Value item = pqueue.pop();
+ if (!(item == e.popValue)) {
+ std::cerr << "ERROR: queue " << pqueue.getName()
+ << " gave incorrect value " << item << std::endl;
+ exit(1);
+ }
+ } else {
+ const Value* begin = &_mem[e.begin];
+ pqueue.push(begin, begin + e.size);
+ }
+ }
+ }
+ clock_t timeEnd = clock();
+
+ SimData data;
+ data.name = pqueue.getName();
+ data.memoryUse = pqueue.getMemoryUse();
+ data.comparisons = pqueue.getComparisons();
+ data.mseconds = (unsigned long)
+ ((double(timeEnd) - timeBegin) * 1000) / CLOCKS_PER_SEC;
+ _data.push_back(data);
+ if (printData)
+ data.print(std::cerr);
+}
+
+#endif
diff --git a/src/pqsim/StlSetModel.h b/src/pqsim/StlSetModel.h
new file mode 100755
index 0000000..24fbdc2
--- /dev/null
+++ b/src/pqsim/StlSetModel.h
@@ -0,0 +1,10 @@
+#ifndef STL_SET_MODEL_GUARD
+#define STL_SET_MODEL_GUARD
+
+#include "Model.h"
+#include "mathic/StlSet.h"
+
+template<bool OnSpans>
+class StlSetModel : public Model<OnSpans, false, false, mathic::StlSet> {};
+
+#endif
diff --git a/src/pqsim/TourTreeModel.h b/src/pqsim/TourTreeModel.h
new file mode 100755
index 0000000..109a913
--- /dev/null
+++ b/src/pqsim/TourTreeModel.h
@@ -0,0 +1,16 @@
+#ifndef TOUR_TREE_MODEL_GUARD
+#define TOUR_TREE_MODEL_GUARD
+
+#include "mathic/TourTree.h"
+#include "Model.h"
+
+template<bool FastIndex>
+struct TourTreeModelBase {
+ static const bool fastIndex = FastIndex;
+};
+
+template<bool OnSpans, bool FastIndex>
+class TourTreeModel : public Model<
+ OnSpans, false, true, mathic::TourTree, TourTreeModelBase<FastIndex> > {};
+
+#endif
diff --git a/src/pqsim/pqMain.cpp b/src/pqsim/pqMain.cpp
new file mode 100755
index 0000000..a211ddd
--- /dev/null
+++ b/src/pqsim/pqMain.cpp
@@ -0,0 +1,65 @@
+#include "stdinc.h"
+
+#include "StlSetModel.h"
+#include "HeapModel.h"
+#include "GeobucketModel.h"
+#include "TourTreeModel.h"
+#include "Simulator.h"
+#include <iostream>
+#include <ctime>
+
+namespace {
+ size_t toInt(const char* str) {
+ std::istringstream in(str);
+ size_t i;
+ in >> i;
+ return i;
+ }
+}
+
+int main(int argc, const char** args) {
+ srand(static_cast<unsigned int>(time(0)));
+ srand(0);
+ if (argc < 4) {
+ std::cerr << "usage: elements span-length target-avg-size\n";
+ return 0;
+ }
+ size_t elements = toInt(args[1]);
+ size_t spanSize = toInt(args[2]);
+ size_t avgOrInitialSize = toInt(args[3]);
+ size_t dups = 30;
+ if (argc >= 5)
+ dups = toInt(args[4]);
+
+ size_t repeats = 500;
+ IF_DEBUG(repeats = 2;);
+
+ std::cerr << "Generating simulation..." << std::endl;
+ Simulator sim(repeats);
+ //sim.orderSpans(elements / spanSize, spanSize, avgOrInitialSize);
+ //sim.randomSpans(elements / spanSize, spanSize, avgOrInitialSize);
+ sim.dupSpans(elements, spanSize, avgOrInitialSize, dups);
+ sim.printEventSummary(std::cerr);
+ //sim.printEvents(std::cerr);
+ std::cerr << '\n' << std::endl;
+
+#ifdef DEBUG
+ {TourTreeModel<0,0> x; sim.run(x);}
+ {HeapModel<0,0,0> x; sim.run(x);}
+#else
+ {TourTreeModel<1,0> x; sim.run(x);}
+ {TourTreeModel<0,0> x; sim.run(x);}
+ {GeobucketModel<0,0,0,0,0,0,0> x(4, 32); sim.run(x);}
+ {GeobucketModel<0,0,0,0,0,0,0> x(2, 32); sim.run(x);}
+ {GeobucketModel<0,0,0,1,0,0,0> x(4, 32); sim.run(x);}
+ {StlSetModel<1> x; sim.run(x);}
+ {StlSetModel<0> x; sim.run(x);}
+ {HeapModel<0,0,0> x; sim.run(x);}
+ {HeapModel<1,0,0> x; sim.run(x);}
+ {HeapModel<0,1,0> x; sim.run(x);}
+ {HeapModel<1,1,0> x; sim.run(x);}
+#endif
+
+ sim.printData(std::cout);
+ return 0;
+}
diff --git a/src/pqsim/pqMain.h b/src/pqsim/pqMain.h
new file mode 100755
index 0000000..57ec9e8
--- /dev/null
+++ b/src/pqsim/pqMain.h
@@ -0,0 +1,6 @@
+#ifndef PQ_MAIN
+#define PQ_MAIN
+
+int main(int argc, const char** args);
+
+#endif
diff --git a/src/pqsim/stdinc.h b/src/pqsim/stdinc.h
new file mode 100755
index 0000000..da6f62a
--- /dev/null
+++ b/src/pqsim/stdinc.h
@@ -0,0 +1,48 @@
+#ifdef STDINC_GUARD
+#error stdinc.h included twice
+#endif
+#define STDINC_GUARD
+
+#ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++.
+#pragma warning (push, 1) // Reduce warning level for GMP headers.
+#endif
+
+#ifndef _MSC_VER
+#define NO_INLINE
+#endif
+
+#ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++.
+#define NO_INLINE __declspec(noinline)
+#pragma warning (pop) // Go back to previous warning level.
+#pragma warning (disable: 4996) // std::copy is flagged as dangerous.
+#pragma warning (disable: 4290) // VC++ ignores throw () specification.
+#pragma warning (disable: 4127) // Warns about using "while (true)".
+#pragma warning (disable: 4100) // Warns about unused parameters.
+#pragma warning (disable: 4800) // Warns on int to bool conversion.
+#pragma warning (disable: 4146) // Warns on unary minus on unsigned (bit trick)
+
+// This warning warns about using the this pointer in base member
+// initializer lists. This is a pretty good warning as that can
+// obviously easily go wrong, but it is pretty useful to do as well,
+// so the warning is turned off.
+#pragma warning (disable: 4355)
+
+#ifdef _DEBUG
+#define DEBUG
+#endif
+
+#endif
+
+#include <cstddef>
+#include <memory>
+
+#ifdef DEBUG
+#include <iostream> // Useful for debugging.
+#define PRINT
+#include <cassert>
+#define ASSERT(X) assert(X);
+#define IF_DEBUG(X) X
+#else
+#define ASSERT(X)
+#define IF_DEBUG(X)
+#endif
diff --git a/src/test/DivFinder.cpp b/src/test/DivFinder.cpp
new file mode 100755
index 0000000..ca920ae
--- /dev/null
+++ b/src/test/DivFinder.cpp
@@ -0,0 +1,10 @@
+#include "divsim/stdinc.h"
+#include "mathic/KDTree.h"
+#include <gtest/gtest.h>
+
+#include "mathic/DivList.h"
+#include "divsim/KDTreeModel.h"
+
+TEST(DivFinder, NoOp) {
+ KDTreeModel<1,1,1,1,1> model(1, 1, 0, 0, 1.0, 1000);
+};
diff --git a/src/test/gtestInclude.cpp b/src/test/gtestInclude.cpp
new file mode 100755
index 0000000..a14f48f
--- /dev/null
+++ b/src/test/gtestInclude.cpp
@@ -0,0 +1,10 @@
+// Includes a file from gtest that pulls in all of the implementation
+// of gtest. The gtest docs recommend building gtest individually for
+// each program rather than using an installed gtest and this is as
+// easy a way of doing it as any. Especially because it guarantees that
+// the compiler flags are the same, which is the whole point of the
+// recommendation to build gtest for each program.
+
+// the .. goes back from the include/ directory of gtest so we can
+// enter the src directory.
+#include <../src/gtest-all.cc>
diff --git a/src/test/testMain.cpp b/src/test/testMain.cpp
new file mode 100755
index 0000000..4d820af
--- /dev/null
+++ b/src/test/testMain.cpp
@@ -0,0 +1,6 @@
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/mathic.git
More information about the debian-science-commits
mailing list