├── .gitignore ├── Makefile.am ├── README.md ├── autogen.sh ├── build ├── autotools │ ├── .gitignore │ ├── m4 │ │ └── .gitignore │ └── mathic.pc.in └── vs12 │ ├── mathic-lib │ ├── mathic-lib.vcxproj │ └── mathic-lib.vcxproj.filters │ ├── mathic-test │ ├── mathic-test.vcxproj │ └── mathic-test.vcxproj.filters │ └── mathic.sln ├── configure.ac ├── fixspace ├── include └── mathic │ ├── mathic.cpp │ └── mathic.h ├── libs └── .gitignore ├── replace └── src ├── divsim ├── DivListModel.h ├── KDTreeModel.h ├── Monomial.h ├── Simulation.cpp ├── Simulation.h ├── divMain.cpp ├── divMain.h └── stdinc.h ├── mathic.cpp ├── mathic.h ├── mathic ├── Action.cpp ├── Action.h ├── BinaryKDTree.h ├── BitTriangle.cpp ├── BitTriangle.h ├── BoolParameter.cpp ├── BoolParameter.h ├── CliParameter.cpp ├── CliParameter.h ├── CliParser.cpp ├── CliParser.h ├── ColumnPrinter.cpp ├── ColumnPrinter.h ├── ComTree.h ├── Comparer.h ├── DivFinder.h ├── DivList.h ├── DivMask.cpp ├── DivMask.h ├── GeoFront.h ├── Geobucket.h ├── HashTable.h ├── Heap.h ├── HelpAction.cpp ├── HelpAction.h ├── IntegerParameter.cpp ├── IntegerParameter.h ├── KDEntryArray.h ├── KDTree.h ├── NameFactory.h ├── PackedKDTree.h ├── PairQueue.h ├── StlSet.h ├── StringParameter.cpp ├── StringParameter.h ├── Timer.cpp ├── Timer.h ├── TourTree.h ├── display.cpp ├── display.h ├── error.cpp ├── error.h ├── main.cpp └── stdinc.h ├── pqsim ├── GeobucketModel.h ├── HeapModel.h ├── Item.cpp ├── Item.h ├── Model.cpp ├── Model.h ├── Simulator.cpp ├── Simulator.h ├── StlSetModel.h ├── TourTreeModel.h ├── pqMain.cpp ├── pqMain.h └── stdinc.h └── test ├── BitTriangle.cpp ├── DivFinder.cpp ├── HashTable.cpp ├── PairQueue.cpp ├── gtestInclude.cpp └── testMain.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | 9 | # Compiled Static libraries 10 | *.lai 11 | *.la 12 | *.a 13 | 14 | # Emacs backup files 15 | \#*\# 16 | *~ 17 | 18 | # Autotools generated files 19 | config.log 20 | config.status 21 | libtool 22 | .deps/ 23 | .dirstamp 24 | aclocal.m4 25 | autom4te.cache/ 26 | Makefile.in 27 | Makefile 28 | configure 29 | .libs/ 30 | 31 | # Visual studio generated files 32 | *.suo 33 | *.sdf 34 | *.opensdf 35 | *.vcxproj.user 36 | output/ 37 | 38 | # Configure build targets 39 | deb/ 40 | debnoass/ 41 | pro/ 42 | rel/ 43 | relass/ 44 | 45 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # options passed to aclocal, which is a tool for making macroes visible to 2 | # autoconf. We use -I to tell aclocal where we put the local macros. 3 | ACLOCAL_AMFLAGS = -I build/autotools/m4 4 | 5 | # Options passed to the C and C++ PreProcessor (CPP) and compiler 6 | AM_CPPFLAGS = -I${top_srcdir}/ 7 | libmathic_la_CPPFLAGS = $(DEPS_CFLAGS) 8 | 9 | # tell Libtool what the name of the library is. 10 | lib_LTLIBRARIES = libmathic.la 11 | 12 | # set the C++ compiler to include src/ 13 | AM_CXXFLAGS=-I$(top_srcdir)/src/ -std=gnu++0x 14 | 15 | # libraries that are needed by this library 16 | libmathic_la_LIBADD= $(DEPS_LIBS) 17 | 18 | # the sources that are built to make libmathic. 19 | libmathic_la_SOURCES = src/mathic/Timer.cpp \ 20 | src/mathic/ColumnPrinter.cpp src/mathic/DivMask.cpp \ 21 | src/mathic/Action.cpp src/mathic/BoolParameter.cpp \ 22 | src/mathic/CliParameter.cpp src/mathic/CliParser.cpp \ 23 | src/mathic/error.cpp src/mathic/HelpAction.cpp \ 24 | src/mathic/IntegerParameter.cpp src/mathic/StringParameter.cpp \ 25 | src/mathic/display.cpp src/mathic/BitTriangle.cpp src/mathic.cpp 26 | 27 | # The headers that libmathic installs. 28 | # Normally, automake strips the path from the files when installing them, 29 | # so src/mathic/x.h gets installed as just x.h. 30 | mathicA_include_HEADERS = src/mathic.h 31 | mathicA_includedir = $(includedir) 32 | # install remaining headers into subdirectory of the include dir 33 | mathicB_includedir = \ 34 | $(includedir)/mathic 35 | mathicB_include_HEADERS = src/mathic/Action.h src/mathic/Geobucket.h \ 36 | src/mathic/BinaryKDTree.h src/mathic/GeoFront.h \ 37 | src/mathic/BoolParameter.h src/mathic/Heap.h \ 38 | src/mathic/CliParameter.h src/mathic/HelpAction.h \ 39 | src/mathic/CliParser.h src/mathic/IntegerParameter.h \ 40 | src/mathic/ColumnPrinter.h src/mathic/KDEntryArray.h \ 41 | src/mathic/Comparer.h src/mathic/KDTree.h src/mathic/ComTree.h \ 42 | src/mathic/NameFactory.h src/mathic/display.h \ 43 | src/mathic/PackedKDTree.h src/mathic/DivFinder.h src/mathic/stdinc.h \ 44 | src/mathic/DivList.h src/mathic/StlSet.h src/mathic/DivMask.h \ 45 | src/mathic/StringParameter.h \ 46 | src/mathic/Timer.h src/mathic/error.h src/mathic/TourTree.h \ 47 | src/mathic/BitTriangle.h \ 48 | src/mathic/PairQueue.h \ 49 | src/mathic/HashTable.h 50 | 51 | pkgconfigdir = $(libdir)/pkgconfig 52 | pkgconfig_DATA = build/autotools/mathic.pc 53 | 54 | # When making a distribution file, Automake knows to include all files 55 | # that are necessary to build the project. EXTRA_DIST specifies files 56 | # to include beyond those used in the build process. 57 | EXTRA_DIST = autogen.sh 58 | 59 | # tell automake what programs are there that are not built automatically 60 | EXTRA_PROGRAMS = pqsim divsim 61 | 62 | # set up the divisor query simulation. Listing the headers in sources 63 | # ensure that those files are included in distributions. 64 | divsim_CPPFLAGS = $(DEPS_CFLAGS) 65 | divsim_SOURCES = src/divsim/divMain.cpp src/divsim/Simulation.cpp \ 66 | src/divsim/DivListModel.h src/divsim/KDTreeModel.h \ 67 | src/divsim/Simulation.h src/divsim/divMain.h src/divsim/Monomial.h \ 68 | src/divsim/stdinc.h 69 | divsim_LDADD = $(top_builddir)/libmathic.la 70 | 71 | # set up the priority queue simulation. Listing the headers in sources 72 | # ensure that those files are included in distributions. 73 | pqsim_CPPFLAGS = $(DEPS_CFLAGS) 74 | pqsim_SOURCES = src/pqsim/Item.cpp src/pqsim/Model.cpp \ 75 | src/pqsim/pqMain.cpp src/pqsim/Simulator.cpp \ 76 | src/pqsim/GeobucketModel.h src/pqsim/Model.h src/pqsim/stdinc.h \ 77 | src/pqsim/HeapModel.h src/pqsim/pqMain.h src/pqsim/StlSetModel.h \ 78 | src/pqsim/Item.h src/pqsim/Simulator.h src/pqsim/TourTreeModel.h 79 | pqsim_LDADD = $(top_builddir)/libmathic.la 80 | 81 | 82 | # set up tests to run on "make check" 83 | if with_gtest 84 | 85 | TESTS=unittest 86 | check_PROGRAMS=$(TESTS) 87 | 88 | unittest_CPPFLAGS = $(DEPS_CFLAGS) 89 | unittest_CXXFLAGS = -I$(top_srcdir)/src/ -std=gnu++0x 90 | unittest_LDADD = $(DEPS_LIBS) 91 | unittest_LDFLAGS= $(top_builddir)/libmathic.la 92 | 93 | test_LIBS= 94 | unittest_SOURCES=src/test/DivFinder.cpp src/test/gtestInclude.cpp \ 95 | src/test/testMain.cpp src/test/BitTriangle.cpp \ 96 | src/test/PairQueue.cpp \ 97 | src/test/HashTable.cpp 98 | 99 | else 100 | 101 | check: 102 | @echo 103 | @echo "Configure did not locate gtest, so unittests cannot be run." 104 | 105 | endif 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mathic 2 | ====== 3 | 4 | Mathic is a C++ library of fast data structures designed for use in 5 | Groebner basis computation. This includes data structures for ordering 6 | S-pairs, performing divisor queries and ordering polynomial terms 7 | during polynomial reduction. 8 | 9 | With Mathic you get to use highly optimized code with little effort so 10 | that you can focus more of your time on whatever part of your Groebner 11 | basis implementation that you are interested in. The data structures 12 | use templates to allow you to use them with whatever representation of 13 | monomials/terms and coefficients that your code uses. In fact the only 14 | places where Mathic defines its own monomials/terms is in the test 15 | code and example code. Currently only dense representations of 16 | terms/monomials are suitable since Mathic will frequently ask "what is 17 | the exponent of variable number x in this term/monomial?". 18 | 19 | The paper "Practical Grobner Basis Computation" describes the data 20 | structures from a high level. It was presented at ISSAC 2012 and is 21 | available at http://arxiv.org/abs/1206.6940 22 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | srcdir="`dirname '$0'`" 3 | 4 | autoreconf --verbose --install --force $srcdir 5 | -------------------------------------------------------------------------------- /build/autotools/.gitignore: -------------------------------------------------------------------------------- 1 | # Autotools generated files 2 | ar-lib 3 | config.guess 4 | config.sub 5 | depcomp 6 | install-sh 7 | ltmain.sh 8 | mathic-*.pc 9 | missing 10 | -------------------------------------------------------------------------------- /build/autotools/m4/.gitignore: -------------------------------------------------------------------------------- 1 | # Autotools generated files 2 | libtool.m4 3 | ltoptions.m4 4 | ltsugar.m4 5 | ltversion.m4 6 | lt~obsolete.m4 7 | -------------------------------------------------------------------------------- /build/autotools/mathic.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: mathic 7 | Description: C++ library of symbolic algebra data structures for use in Groebner basis computation. 8 | URL: https://github.com/broune/mathic 9 | Requires: memtailor 10 | Version: @PACKAGE_VERSION@ 11 | Libs: -L${libdir} -lmathic 12 | Cflags: -I${includedir}/ 13 | -------------------------------------------------------------------------------- /build/vs12/mathic-lib/mathic-lib.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | Header Files 106 | 107 | 108 | Header Files 109 | 110 | 111 | Header Files 112 | 113 | 114 | Header Files 115 | 116 | 117 | Header Files 118 | 119 | 120 | Header Files 121 | 122 | 123 | Header Files 124 | 125 | 126 | Header Files 127 | 128 | 129 | Header Files 130 | 131 | 132 | Header Files 133 | 134 | 135 | Header Files 136 | 137 | 138 | Header Files 139 | 140 | 141 | Header Files 142 | 143 | 144 | Header Files 145 | 146 | 147 | Header Files 148 | 149 | 150 | -------------------------------------------------------------------------------- /build/vs12/mathic-test/mathic-test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | -------------------------------------------------------------------------------- /build/vs12/mathic.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathic-lib", "mathic-lib\mathic-lib.vcxproj", "{BEBD36F1-A124-4C01-8E67-3208D4472661}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathic-test", "mathic-test\mathic-test.vcxproj", "{9B09A868-B169-43E8-AFF9-D2F12657ABCF}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {BEBD36F1-A124-4C01-8E67-3208D4472661} = {BEBD36F1-A124-4C01-8E67-3208D4472661} 9 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551} = {534C44F8-BA0A-4AF0-95F1-260CA8EF3551} 10 | EndProjectSection 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memtailor-lib", "..\..\..\memtailor\build\vs12\memtailor-lib\memtailor-lib.vcxproj", "{534C44F8-BA0A-4AF0-95F1-260CA8EF3551}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Win32 = Debug|Win32 17 | Debug|x64 = Debug|x64 18 | Debug-NoAssert|Win32 = Debug-NoAssert|Win32 19 | Debug-NoAssert|x64 = Debug-NoAssert|x64 20 | Release|Win32 = Release|Win32 21 | Release|x64 = Release|x64 22 | Release-Assert|Win32 = Release-Assert|Win32 23 | Release-Assert|x64 = Release-Assert|x64 24 | WarningAsError|Win32 = WarningAsError|Win32 25 | WarningAsError|x64 = WarningAsError|x64 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug|Win32.ActiveCfg = Debug|Win32 29 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug|Win32.Build.0 = Debug|Win32 30 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug|x64.ActiveCfg = Debug|x64 31 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug|x64.Build.0 = Debug|x64 32 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug-NoAssert|Win32.ActiveCfg = Debug-NoAssert|Win32 33 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug-NoAssert|Win32.Build.0 = Debug-NoAssert|Win32 34 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug-NoAssert|x64.ActiveCfg = Debug-NoAssert|x64 35 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug-NoAssert|x64.Build.0 = Debug-NoAssert|x64 36 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release|Win32.ActiveCfg = Release|Win32 37 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release|Win32.Build.0 = Release|Win32 38 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release|x64.ActiveCfg = Release|x64 39 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release|x64.Build.0 = Release|x64 40 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release-Assert|Win32.ActiveCfg = Release-Assert|Win32 41 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release-Assert|Win32.Build.0 = Release-Assert|Win32 42 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release-Assert|x64.ActiveCfg = Release-Assert|x64 43 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release-Assert|x64.Build.0 = Release-Assert|x64 44 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.WarningAsError|Win32.ActiveCfg = WarningAsError|Win32 45 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.WarningAsError|Win32.Build.0 = WarningAsError|Win32 46 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.WarningAsError|x64.ActiveCfg = WarningAsError|x64 47 | {BEBD36F1-A124-4C01-8E67-3208D4472661}.WarningAsError|x64.Build.0 = WarningAsError|x64 48 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug|Win32.ActiveCfg = Debug|Win32 49 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug|Win32.Build.0 = Debug|Win32 50 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug|x64.ActiveCfg = Debug|x64 51 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug|x64.Build.0 = Debug|x64 52 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug-NoAssert|Win32.ActiveCfg = Debug-NoAssert|Win32 53 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug-NoAssert|Win32.Build.0 = Debug-NoAssert|Win32 54 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug-NoAssert|x64.ActiveCfg = Debug-NoAssert|x64 55 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug-NoAssert|x64.Build.0 = Debug-NoAssert|x64 56 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release|Win32.ActiveCfg = Release|Win32 57 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release|Win32.Build.0 = Release|Win32 58 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release|x64.ActiveCfg = Release|x64 59 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release|x64.Build.0 = Release|x64 60 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release-Assert|Win32.ActiveCfg = Release-Assert|Win32 61 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release-Assert|Win32.Build.0 = Release-Assert|Win32 62 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release-Assert|x64.ActiveCfg = Release-Assert|x64 63 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release-Assert|x64.Build.0 = Release-Assert|x64 64 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.WarningAsError|Win32.ActiveCfg = WarningAsError|Win32 65 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.WarningAsError|Win32.Build.0 = WarningAsError|Win32 66 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.WarningAsError|x64.ActiveCfg = WarningAsError|x64 67 | {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.WarningAsError|x64.Build.0 = WarningAsError|x64 68 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug|Win32.ActiveCfg = Debug|Win32 69 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug|Win32.Build.0 = Debug|Win32 70 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug|x64.ActiveCfg = Debug|x64 71 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug|x64.Build.0 = Debug|x64 72 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug-NoAssert|Win32.ActiveCfg = Debug-NoAssert|Win32 73 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug-NoAssert|Win32.Build.0 = Debug-NoAssert|Win32 74 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug-NoAssert|x64.ActiveCfg = Debug-NoAssert|x64 75 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug-NoAssert|x64.Build.0 = Debug-NoAssert|x64 76 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release|Win32.ActiveCfg = Release|Win32 77 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release|Win32.Build.0 = Release|Win32 78 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release|x64.ActiveCfg = Release|x64 79 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release|x64.Build.0 = Release|x64 80 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release-Assert|Win32.ActiveCfg = Release-Assert|Win32 81 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release-Assert|Win32.Build.0 = Release-Assert|Win32 82 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release-Assert|x64.ActiveCfg = Release-Assert|x64 83 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release-Assert|x64.Build.0 = Release-Assert|x64 84 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.WarningAsError|Win32.ActiveCfg = WarningAsError|Win32 85 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.WarningAsError|Win32.Build.0 = WarningAsError|Win32 86 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.WarningAsError|x64.ActiveCfg = WarningAsError|x64 87 | {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.WarningAsError|x64.Build.0 = WarningAsError|x64 88 | EndGlobalSection 89 | GlobalSection(SolutionProperties) = preSolution 90 | HideSolutionNode = FALSE 91 | EndGlobalSection 92 | EndGlobal 93 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl AC_INIT sets up autoconf and must be first macro. 2 | AC_INIT([mathic], [1.0]) # package, version, bug-report-email 3 | 4 | # Check that memtailor is installed and locate it 5 | PKG_CHECK_MODULES([MEMTAILOR], [memtailor]) 6 | 7 | dnl ----- The gtest dependency 8 | 9 | AC_ARG_WITH([gtest], AS_HELP_STRING( 10 | [--with-gtest], [use gtest, which is required for running the unit tests 11 | with make check. The value download, which is the default, downloads 12 | gtest if a gtest source directory cannot be found. Per the recommendation 13 | of the gtest documentation, gtest is compiled with the tests, so an 14 | installed gtest is not usable - you need the gtest source. GTEST_PATH 15 | indicates where to look for gtest and it is also where gtest 16 | will be downloaded to if not found. The default path is srcdir/libs so 17 | that gtest needs to be at srcdir/libs/gtest/ where srcdir is the 18 | base of the directory being configured from.] 19 | )) 20 | 21 | AC_MSG_CHECKING([for gtest]) 22 | AS_IF([test "x$GTEST_PATH" == "x"], [GTEST_PATH="$srcdir/libs"]) 23 | AS_IF([test "x$GTEST_VERSION" == "x"], [GTEST_VERSION="1.6.0"]) 24 | AS_IF([test "x$with_gtest" == "x"], [with_gtest="download"]) 25 | 26 | AS_IF([test "x$with_gtest" == "xdownload"], 27 | [with_gtest="yes"; AC_CHECK_FILE([$GTEST_PATH/gtest/src/gtest-all.cc], [], [ 28 | mkdir -p "$GTEST_PATH"; 29 | ( 30 | cd $GTEST_PATH; 31 | rm -rf gtest-$GTEST_VERSION.zip 32 | wget http://googletest.googlecode.com/files/gtest-$GTEST_VERSION.zip; 33 | unzip gtest-$GTEST_VERSION.zip; 34 | rm gtest-$GTEST_VERSION.zip 35 | rm -rf gtest/ 36 | mv gtest-$GTEST_VERSION/ gtest/ 37 | ); 38 | if test ! -e "$GTEST_PATH/gtest/src/gtest-all.cc"; then 39 | AC_MSG_WARN([Failed to download or extract gtest.]); 40 | with_gtest="no"; 41 | else 42 | with_gtest="yes"; 43 | fi 44 | ])], 45 | [test "x$with_gtest" == "xyes"], [ 46 | AC_CHECK_FILE([$GTEST_PATH/gtest/src/gtest-all.cc], [], [ 47 | AC_MSG_ERROR([could not find gtest source at path $GTEST_PATH.]) 48 | ]) 49 | ], 50 | [test "x$with_gtest" == "xno"], [], 51 | [AC_MSG_ERROR([invalid value $with_gtest for with_gtest.])] 52 | ) 53 | AS_IF([test "x$with_gtest" == "xyes"], 54 | [GTEST_CFLAGS="-I`cd $GTEST_PATH/gtest/include; echo $PWD` -I`cd $GTEST_PATH/gtest/; echo $PWD`"]); 55 | AM_CONDITIONAL(with_gtest, test "x$with_gtest" == "xyes") 56 | 57 | DEPS_CFLAGS="$MEMTAILOR_CFLAGS $GTEST_CFLAGS" 58 | DEPS_LIBS="$MEMTAILOR_LIBS $GTEST_LIBS" 59 | AC_SUBST(DEPS_CFLAGS) 60 | AC_SUBST(DEPS_LIBS) 61 | 62 | # set up information about directories 63 | AC_CONFIG_MACRO_DIR([build/autotools/m4]) # directory of extra autoconf macroes 64 | AC_CONFIG_AUX_DIR([build/autotools]) # directory for auxiliary build tools (install-sh etc) 65 | 66 | # check that source directory is correct 67 | dnl if autoconf is told the source code is in a directory that does not 68 | dnl contain this file then it knows that the directory is wrong. 69 | AC_CONFIG_SRCDIR([src/mathic.h]) 70 | 71 | # Enable optional maintainer mode (off by default) 72 | dnl AM_MAINTAINER_MODE turns off automatic reconstruction of the build 73 | dnl files if the source build files have changed. A developer will want 74 | dnl those automatic reconstructions to happen so that changes to the 75 | dnl build system are actually carried out. However, a user might not 76 | dnl have the tools required to reconfigure and the need for 77 | dnl reconstruction might be spurious if the last-modified date is set 78 | dnl incorrectly on the build files. 79 | dnl 80 | dnl Passing the option [enable] to AM_MAINTAINER_MODE makes the 81 | dnl non-reconstruction feature available, but only when turned on by 82 | dnl passing the option –disable-maintainer-mode. This option is 83 | dnl apparently useful to some package distributors. 84 | AM_MAINTAINER_MODE([enable]) 85 | 86 | # Set up Automake 87 | dnl foreign: do not create the GNU-specific file COPYING and do not complain 88 | dnl that GNU-specific files like NEWS, README, AUTHORS and ChangeLog are 89 | dnl missing. 90 | dnl -Wall: set Automake to emit all warnings it can. Is NOT RELATED to setting 91 | dnl warnings for other tools. For example, it wil not make the compiler 92 | dnl get a -Wall option. 93 | dnl subdir-objects: Put object files in a directory structure based on 94 | dnl the directory structure of the source files. This way, two source 95 | dnl files with the same name in different directories do not conflict. 96 | AM_INIT_AUTOMAKE([foreign subdir-objects -Wall]) 97 | 98 | # if --enable-silent-rules is passed to ./configure or if V=0 is passed 99 | # to make, then the compilation output will be much less verbose making 100 | # it possible to spot warnings and errors as they go by. 101 | AM_SILENT_RULES() 102 | 103 | # Set up the $(LN_S) macro, which creates symbolic links 104 | AC_PROG_LN_S 105 | 106 | # set output variable INSTALL to the name of a BSD-compatible install program. 107 | # Requires install-sh to be present as a fallback, even on systems where 108 | # the fallback is not used. 109 | AC_PROG_INSTALL 110 | 111 | # Locate the C++ compiler. 112 | AC_PROG_CXX 113 | 114 | # Set up LibTool 115 | LT_INIT 116 | 117 | dnl Set the version for the library -- this concerns compatibility of the 118 | dnl source and binary interface of the library and is not the same as the 119 | dnl version of the project. 120 | AC_SUBST([MATHIC_SO_VERSION], [0:0:0]) 121 | 122 | dnl Set up AC_OUTPUT to create each file by copying an input file 123 | dnl while substituting the output variable values. 124 | AC_CONFIG_FILES([Makefile 125 | build/autotools/mathic.pc:build/autotools/mathic.pc.in]) 126 | 127 | dnl Macro that is required to be at the end of any Autoconf script. 128 | dnl Creates config.status and launches it. 129 | AC_OUTPUT 130 | -------------------------------------------------------------------------------- /fixspace: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Does the following operations on the files passed as arguments: 4 | # - Remove trailing space from lines 5 | # - Remove trailing blank lines 6 | # - Remove/convert DOS-style line breaks 7 | # - Expand tabs to spaces with a tabspace of 8 8 | 9 | # I once had an error where the conversion had an error (the computer 10 | # didn't have dos2unix), resulting in the converted files being empty. 11 | # The result was that every file got replaced by an empty file! That 12 | # was not so nice, so this script stops operation as soon as any error 13 | # occurs, and it also checks that only space has been changed before 14 | # it overwrites the original file with a space-fixed version. 15 | 16 | for f in $*; do echo $f; 17 | 18 | tr -d '\r' < $f > __spaceTmp0; 19 | if [ $? != 0 ]; then echo "There was an error removing DOS-style line breaks."; exit 1; fi; 20 | 21 | expand -4 < __spaceTmp0 > __spaceTmp1; 22 | if [ $? != 0 ]; then echo "There was an error expanding tabs."; exit 1; fi; 23 | 24 | sed 's/[[:blank:]]*$//g' < __spaceTmp1 > __spaceTmp2; 25 | if [ $? != 0 ]; then echo "There was an error eliminating trailing space from lines."; exit 1; fi; 26 | 27 | # Make completely sure that we only changed the spaces 28 | diff -EbwB -q $f __spaceTmp2; 29 | if [ $? != 0 ]; then echo "There was an error. Conversion not confirmed correct."; exit 1; fi; 30 | 31 | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' < __spaceTmp2 > __spaceTmp3; 32 | if [ $? != 0 ]; then echo "There was an error eliminating trailing blank lines."; exit 1; fi; 33 | 34 | # We have to do diff twice, because diff will not ignore trailing 35 | # lines that consist only of spaces. It will ignore changes to space and removal of 36 | # completely empty lines, so if we do it twice we get the right thing. 37 | 38 | # Make completely sure that we only changed the spaces 39 | diff -EbwB -q __spaceTmp2 __spaceTmp3; 40 | if [ $? != 0 ]; then echo "There was an error. Conversion not confirmed correct."; exit 1; fi; 41 | 42 | diff -q $f __spaceTmp3 1>/dev/null; 43 | if [ $? != 0 ]; then 44 | mv -f __spaceTmp3 $f; 45 | if [ $? != 0 ]; then echo "There was an error moving fixed file into place."; exit 1; fi; 46 | echo "Fixed space issue for $f." 47 | fi 48 | 49 | rm -f __spaceTmp0 __spaceTmp1 __spaceTmp2 __spaceTmp3; 50 | if [ $? != 0 ]; then echo "There was an error removing temporary files."; exit 1; fi; 51 | done; 52 | -------------------------------------------------------------------------------- /include/mathic/mathic.cpp: -------------------------------------------------------------------------------- 1 | // This implementation file includes all the implementation files needed 2 | // to get MemTailor working. 3 | #include "mathic.h" 4 | #include "../../src/Timer.cpp" 5 | #include "../../src/ColumnPrinter.cpp" 6 | #include "../../src/DivMask.cpp" 7 | #include "../../src/Action.cpp" 8 | #include "../../src/BoolParameter.cpp" 9 | #include "../../src/CliParameter.cpp" 10 | #include "../../src/CliParser.cpp" 11 | #include "../../src/NameFactory.cpp" 12 | #include "../../src/error.cpp" 13 | #include "../../src/HelpAction.cpp" 14 | #include "../../src/IntegerParameter.cpp" 15 | #include "../../src/StringParameter.cpp" 16 | #include "../../src/display.cpp" 17 | -------------------------------------------------------------------------------- /include/mathic/mathic.h: -------------------------------------------------------------------------------- 1 | // Include this file to pull in all external MemTailor files 2 | 3 | // utilities 4 | #include "../../src/Timer.h" 5 | #include "../../src/ColumnPrinter.h" 6 | #include "../../src/error.h" 7 | 8 | // divisor query data structures 9 | #include "../../src/DivList.h" 10 | #include "../../src/KDTree.h" 11 | 12 | // priority queue data structures 13 | #include "../../src/TourTree.h" 14 | #include "../../src/StlSet.h" 15 | #include "../../src/Heap.h" 16 | #include "../../src/Geobucket.h" 17 | 18 | // CLI package 19 | #include "../../src/Action.h" 20 | #include "../../src/BoolParameter.h" 21 | #include "../../src/CliParameter.h" 22 | #include "../../src/CliParser.h" 23 | #include "../../src/HelpAction.h" 24 | #include "../../src/IntegerParameter.h" 25 | #include "../../src/StringParameter.h" 26 | #include "../../src/display.h" 27 | -------------------------------------------------------------------------------- /libs/.gitignore: -------------------------------------------------------------------------------- 1 | gtest/ 2 | -------------------------------------------------------------------------------- /replace: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Running script \"sed s/$1/$2/\"" 3 | for i in 1 2 3; do 4 | /usr/bin/sleep 1; echo -n .; 5 | done 6 | 7 | for f in `ls src/*.cpp src/*.h`; do 8 | echo "Processing $f"; 9 | sed "s/$1/$2/" < $f > $f.tmp 10 | mv $f.tmp $f 11 | done 12 | -------------------------------------------------------------------------------- /src/divsim/DivListModel.h: -------------------------------------------------------------------------------- 1 | #ifndef DIV_ARRAY_MODEL_GUARD 2 | #define DIV_ARRAY_MODEL_GUARD 3 | 4 | #include "Monomial.h" 5 | #include "mathic/DivList.h" 6 | #include 7 | #include 8 | 9 | /** Helper class for DivListModel. */ 10 | template 11 | class DivListModelConfiguration; 12 | 13 | template 14 | class DivListModelConfiguration { 15 | public: 16 | typedef int Exponent; 17 | typedef ::Monomial Monomial; 18 | typedef Monomial Entry; 19 | 20 | DivListModelConfiguration 21 | (size_t varCount, 22 | bool sortOnInsert, 23 | double rebuildRatio, 24 | size_t minRebuild): 25 | _varCount(varCount), 26 | _sortOnInsert(sortOnInsert), 27 | _useAutomaticRebuild((rebuildRatio > 0.0 || minRebuild > 0) && UDM), 28 | _rebuildRatio(rebuildRatio), 29 | _minRebuild(minRebuild), 30 | _expQueryCount(0) {} 31 | 32 | static const bool UseLinkedList = ULL; 33 | static const bool UseDivMask = UDM; 34 | 35 | bool getDoAutomaticRebuilds() const {return _useAutomaticRebuild;} 36 | double getRebuildRatio() const {return _rebuildRatio;} 37 | size_t getRebuildMin() const {return _minRebuild;} 38 | bool getSortOnInsert() const {return _sortOnInsert;} 39 | 40 | 41 | size_t getVarCount() const {return _varCount;} 42 | 43 | Exponent getExponent(const Monomial& monomial, size_t var) const { 44 | ++_expQueryCount; 45 | ASSERT(var < monomial.size()); 46 | return monomial[var]; 47 | } 48 | 49 | bool divides(const Monomial& a, const Monomial& b) const { 50 | for (size_t var = 0; var < getVarCount(); ++var) 51 | if (getExponent(b, var) < getExponent(a, var)) 52 | return false; 53 | return true; 54 | } 55 | 56 | bool isLessThan(const Monomial& a, const Monomial& b) const { 57 | for (size_t var = 0; var < getVarCount(); ++var) { 58 | if (getExponent(a, var) < getExponent(b, var)) 59 | return true; 60 | if (getExponent(b, var) < getExponent(a, var)) 61 | return false; 62 | } 63 | return false; 64 | } 65 | 66 | unsigned long long getExpQueryCount() const {return _expQueryCount;} 67 | 68 | private: 69 | const size_t _varCount; 70 | const bool _sortOnInsert; 71 | const bool _useAutomaticRebuild; 72 | const double _rebuildRatio; 73 | const size_t _minRebuild; 74 | mutable unsigned long long _expQueryCount; 75 | }; 76 | 77 | template 78 | class DivListModel; 79 | 80 | /** An instantiation of the capabilities of DivList. */ 81 | template 82 | class DivListModel { 83 | private: 84 | typedef DivListModelConfiguration C; 85 | typedef mathic::DivList Finder; 86 | public: 87 | typedef typename Finder::iterator iterator; 88 | typedef typename Finder::const_iterator const_iterator; 89 | typedef typename Finder::Monomial Monomial; 90 | typedef typename Finder::Entry Entry; 91 | 92 | DivListModel(size_t varCount, 93 | bool minimizeOnInsert, 94 | bool moveDivisorToFront, 95 | bool sortOnInsert, 96 | double rebuildRatio, 97 | size_t minRebuild): 98 | _finder(C(varCount, sortOnInsert, rebuildRatio, minRebuild)), 99 | _minimizeOnInsert(minimizeOnInsert), 100 | _moveDivisorToFront(moveDivisorToFront) { 101 | ASSERT(!sortOnInsert || !moveDivisorToFront); 102 | } 103 | 104 | void insert(const Entry& entry); 105 | template 106 | void insert(const Entry& entry, MultipleOutput& removed); 107 | 108 | Entry* findDivisor(const Monomial& monomial) { 109 | iterator it = _finder.findDivisorIterator(monomial); 110 | if (_moveDivisorToFront && it != _finder.end()) { 111 | _finder.moveToFront(it); 112 | it = _finder.begin(); 113 | } 114 | return it == end() ? 0 : &*it; 115 | } 116 | const Entry* findDivisor(const Monomial& monomial) const { 117 | return const_cast&>(*this).findDivisor(monomial); 118 | } 119 | 120 | template 121 | void findAllDivisors(const Monomial& monomial, DO& out) { 122 | _finder.findAllDivisors(monomial, out); 123 | } 124 | template 125 | void findAllDivisors(const Monomial& monomial, DO& out) const { 126 | _finder.findAllDivisors(monomial, out); 127 | } 128 | template 129 | void forAll(EO& out) { 130 | _finder.forAll(out); 131 | } 132 | template 133 | void forAll(EO& out) const { 134 | _finder.forAll(out); 135 | } 136 | 137 | std::string getName() const; 138 | 139 | iterator begin() {return _finder.begin();} 140 | const_iterator begin() const {return _finder.begin();} 141 | iterator end() {return _finder.end();} 142 | const_iterator end() const {return _finder.end();} 143 | size_t size() const {return _finder.size();} 144 | 145 | unsigned long long getExpQueryCount() const { 146 | return _finder.getConfiguration().getExpQueryCount(); 147 | } 148 | 149 | private: 150 | Finder _finder; 151 | const bool _minimizeOnInsert; 152 | const bool _moveDivisorToFront; 153 | }; 154 | 155 | template 156 | inline void DivListModel::insert(const Entry& entry) { 157 | if (!_minimizeOnInsert) { 158 | _finder.insert(entry); 159 | return; 160 | } 161 | if (findDivisor(entry) != 0) 162 | return; 163 | bool hasMultiples = _finder.removeMultiples(entry); 164 | _finder.insert(entry); 165 | if (_moveDivisorToFront && hasMultiples) { 166 | iterator it = _finder.end(); 167 | _finder.moveToFront(--it); 168 | } 169 | } 170 | 171 | template 172 | template 173 | inline void DivListModel::insert(const Entry& entry, MO& out) { 174 | if (!_minimizeOnInsert) { 175 | _finder.insert(entry); 176 | return; 177 | } 178 | if (findDivisor(entry) != 0) 179 | return; 180 | bool hasMultiples = _finder.removeMultiples(entry, out); 181 | _finder.insert(entry); 182 | if (_moveDivisorToFront && hasMultiples) { 183 | iterator it = _finder.end(); 184 | _finder.moveToFront(--it); 185 | } 186 | } 187 | 188 | template 189 | inline std::string DivListModel::getName() const { 190 | return _finder.getName() + 191 | (_minimizeOnInsert ? " remin" : " nomin") + 192 | (_moveDivisorToFront ? " toFront" : ""); 193 | } 194 | 195 | #endif 196 | -------------------------------------------------------------------------------- /src/divsim/KDTreeModel.h: -------------------------------------------------------------------------------- 1 | #ifndef K_D_TREE_MODEL_GUARD 2 | #define K_D_TREE_MODEL_GUARD 3 | 4 | #include "Monomial.h" 5 | #include "mathic/KDTree.h" 6 | #include 7 | #include 8 | 9 | template< 10 | bool UseDivMask, 11 | bool UseTreeDivMask, 12 | bool PackedTree, 13 | size_t LeafSize, 14 | bool AllowRemovals> 15 | class KDTreeModelConfiguration; 16 | 17 | /** Helper class for KDTreeModel. */ 18 | template 19 | class KDTreeModelConfiguration { 20 | public: 21 | typedef int Exponent; 22 | typedef ::Monomial Monomial; 23 | typedef Monomial Entry; 24 | 25 | KDTreeModelConfiguration 26 | (size_t varCount, 27 | bool sortOnInsert, 28 | bool useDivisorCache, 29 | double rebuildRatio, 30 | size_t minRebuild): 31 | _varCount(varCount), 32 | _sortOnInsert(sortOnInsert), 33 | _useDivisorCache(useDivisorCache), 34 | _useAutomaticRebuild((rebuildRatio > 0.0 || minRebuild > 0) && UDM), 35 | _rebuildRatio(rebuildRatio), 36 | _minRebuild(minRebuild), 37 | _expQueryCount(0) { 38 | ASSERT(rebuildRatio >= 0); 39 | } 40 | 41 | size_t getVarCount() const {return _varCount;} 42 | bool getSortOnInsert() const {return _sortOnInsert;} 43 | 44 | Exponent getExponent(const Monomial& monomial, size_t var) const { 45 | ++_expQueryCount; 46 | ASSERT(var < monomial.size()); 47 | return monomial[var]; 48 | } 49 | 50 | NO_PINLINE bool divides(const Monomial& a, const Monomial& b) const { 51 | for (size_t var = 0; var < getVarCount(); ++var) 52 | if (getExponent(b, var) < getExponent(a, var)) 53 | return false; 54 | return true; 55 | } 56 | 57 | bool isLessThan(const Monomial& a, const Monomial& b) const { 58 | for (size_t var = 0; var < getVarCount(); ++var) { 59 | if (getExponent(a, var) < getExponent(b, var)) 60 | return true; 61 | if (getExponent(b, var) < getExponent(a, var)) 62 | return false; 63 | } 64 | return false; 65 | } 66 | 67 | size_t getLeafSize() const {return LeafSize;} 68 | bool getUseDivisorCache() const {return _useDivisorCache;} 69 | bool getDoAutomaticRebuilds() const {return _useAutomaticRebuild;} 70 | double getRebuildRatio() const {return _rebuildRatio;} 71 | size_t getRebuildMin() const {return _minRebuild;} 72 | 73 | static const bool UseDivMask = UDM; 74 | static const bool UseTreeDivMask = UTDM; 75 | static const bool PackedTree = PT; 76 | static const size_t LeafSize = LS; 77 | static const bool AllowRemovals = AR; 78 | 79 | unsigned long long getExpQueryCount() const {return _expQueryCount;} 80 | 81 | private: 82 | const size_t _varCount; 83 | const bool _sortOnInsert; 84 | const bool _useDivisorCache; 85 | const bool _useAutomaticRebuild; 86 | const double _rebuildRatio; 87 | const size_t _minRebuild; 88 | mutable unsigned long long _expQueryCount; 89 | }; 90 | 91 | /** An instantiation of the capabilities of KDTree. */ 92 | template< 93 | bool UseDivMask, 94 | bool UseTreeDivMask, 95 | bool PackedTree, 96 | size_t LeafSize, 97 | bool AllowRemovals 98 | > 99 | class KDTreeModel { 100 | private: 101 | typedef KDTreeModelConfiguration 102 | C; 103 | typedef mathic::KDTree Finder; 104 | public: 105 | typedef typename Finder::Monomial Monomial; 106 | typedef typename Finder::Entry Entry; 107 | 108 | KDTreeModel(size_t varCount, 109 | bool minimizeOnInsert, 110 | bool sortOnInsert, 111 | bool useDivisorCache, 112 | double rebuildRatio, 113 | size_t minRebuild): 114 | _finder(C(varCount, sortOnInsert, useDivisorCache, rebuildRatio, minRebuild)), 115 | _minimizeOnInsert(minimizeOnInsert) { 116 | ASSERT(!UseTreeDivMask || UseDivMask); 117 | } 118 | 119 | 120 | void insert(const Entry& entry); 121 | template 122 | void insert(const Entry& entry, MultipleOutput& removed); 123 | 124 | Entry* findDivisor(const Monomial& monomial) { 125 | return _finder.findDivisor(monomial); 126 | } 127 | const Entry* findDivisor(const Monomial& monomial) const { 128 | return _finder.findDivisor(monomial); 129 | } 130 | std::string getName() const; 131 | 132 | template 133 | void findAllDivisors(const Monomial& monomial, DO& out) { 134 | _finder.findAllDivisors(monomial, out); 135 | } 136 | template 137 | void findAllDivisors(const Monomial& monomial, DO& out) const { 138 | _finder.findAllDivisors(monomial, out); 139 | } 140 | template 141 | void forAll(EO& out) { 142 | _finder.forAll(out); 143 | } 144 | template 145 | void forAll(EO& out) const { 146 | _finder.forAll(out); 147 | } 148 | size_t size() const {return _finder.size();} 149 | 150 | unsigned long long getExpQueryCount() const { 151 | return _finder.getConfiguration().getExpQueryCount(); 152 | } 153 | 154 | class Comparer; 155 | 156 | private: 157 | Finder _finder; 158 | bool _minimizeOnInsert; 159 | }; 160 | 161 | template 162 | inline void KDTreeModel::insert(const Entry& entry) { 163 | if (!_minimizeOnInsert) { 164 | _finder.insert(entry); 165 | return; 166 | } 167 | if (findDivisor(entry) != 0) 168 | return; 169 | _finder.removeMultiples(entry); 170 | _finder.insert(entry); 171 | } 172 | 173 | template 174 | template 175 | inline void KDTreeModel:: 176 | insert(const Entry& entry, MultipleOutput& removed) { 177 | if (!_minimizeOnInsert) { 178 | _finder.insert(entry); 179 | return; 180 | } 181 | if (findDivisor(entry) != 0) 182 | return; 183 | _finder.removeMultiples(entry, removed); 184 | _finder.insert(entry); 185 | } 186 | 187 | template 188 | inline std::string KDTreeModel::getName() const { 189 | return _finder.getName() + 190 | (_minimizeOnInsert ? " remin" : " nomin"); 191 | } 192 | 193 | #endif 194 | -------------------------------------------------------------------------------- /src/divsim/Monomial.h: -------------------------------------------------------------------------------- 1 | #ifndef MONOMIAL_GUARD 2 | #define MONOMIAL_GUARD 3 | 4 | #include 5 | #include 6 | 7 | class Monomial { 8 | public: 9 | typedef int Exponent; 10 | 11 | Monomial(): _exponents(0) {IF_DEBUG(_size = 0);} 12 | Monomial(std::vector& v): _exponents(&v[0]) { 13 | IF_DEBUG(_size = v.size()); 14 | } 15 | 16 | inline Exponent& operator[](size_t index) { 17 | ASSERT(index < _size); 18 | return _exponents[index]; 19 | } 20 | inline const Exponent& operator[](size_t index) const { 21 | ASSERT(index < _size); 22 | return _exponents[index]; 23 | } 24 | 25 | const Exponent* getPointer() const {return _exponents;} 26 | 27 | #ifdef DEBUG 28 | size_t size() const {return _size;} 29 | bool operator==(const Monomial& m) const {return _exponents == m._exponents;} 30 | bool operator<(const Monomial& m) const {return _exponents < m._exponents;} 31 | #endif 32 | 33 | private: 34 | #ifdef DEBUG 35 | size_t _size; 36 | #endif 37 | Exponent* _exponents; 38 | }; 39 | 40 | inline std::ostream& operator<<(std::ostream& out, const Monomial& monomial) { 41 | #ifdef DEBUG 42 | out << "(Monomial:"; 43 | for (size_t i = 0; i < monomial.size(); ++i) 44 | out << ' ' << monomial[i]; 45 | out << ')'; 46 | #else 47 | out << "(Monomial)"; 48 | #endif 49 | return out; 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/divsim/Simulation.cpp: -------------------------------------------------------------------------------- 1 | #include "stdinc.h" 2 | #include "Simulation.h" 3 | 4 | #include "mathic/ColumnPrinter.h" 5 | #include 6 | #include 7 | 8 | namespace { 9 | void makeRandom(std::vector& monomial) { 10 | for (size_t var = 0; var < monomial.size(); ++var) 11 | monomial[var] = rand() % 1000; 12 | } 13 | } 14 | 15 | void Simulation::makeStandard 16 | (size_t varCount, size_t inserts, size_t queries, bool findAll) { 17 | srand(0); 18 | 19 | _findAll = findAll; 20 | _varCount = varCount; 21 | _events.clear(); 22 | for (size_t i = 0; i < inserts + queries; ++i) { 23 | /*Event event2; 24 | event2._type = StateUnknown; 25 | _events.push_back(event2);*/ 26 | 27 | Event event; 28 | event._monomial.resize(varCount); 29 | makeRandom(event._monomial); 30 | event._type = (i <= inserts ? InsertUnknown : QueryUnknown); 31 | _events.push_back(event); 32 | } 33 | } 34 | 35 | void Simulation::printData(std::ostream& out) const { 36 | std::vector sorted(_data); 37 | std::sort(sorted.begin(), sorted.end()); 38 | out << "*** Simulation outcome for " 39 | << _repeats << " repeats ***" << std::endl; 40 | mic::ColumnPrinter pr; 41 | pr.addColumn(true); 42 | pr.addColumn(false, " ", "ms"); 43 | pr.addColumn(false, " ", "eqs"); 44 | for (std::vector::const_iterator it = sorted.begin(); 45 | it != sorted.end(); ++it) { 46 | pr[0] << it->_name << '\n'; 47 | pr[1] << mic::ColumnPrinter::commafy(it->_mseconds) << '\n'; 48 | pr[2] << mic::ColumnPrinter::commafy(it->_expQueryCount) << '\n'; 49 | } 50 | pr.print(out); 51 | } 52 | 53 | void Simulation::SimData::print(std::ostream& out) { 54 | out << _name 55 | << " " << mic::ColumnPrinter::commafy(_mseconds) << " ms" 56 | << " " << mic::ColumnPrinter::commafy(_expQueryCount) << " eqs" 57 | << '\n'; 58 | } 59 | 60 | bool Simulation::SimData::operator<(const SimData& sd) const { 61 | return _mseconds < sd._mseconds; 62 | } 63 | -------------------------------------------------------------------------------- /src/divsim/Simulation.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMULATION_GUARD 2 | #define SIMULATION_GUARD 3 | 4 | #include "Monomial.h" 5 | #include "mathic/Timer.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class Simulation { 12 | public: 13 | Simulation(size_t repeats, bool printPartialData): 14 | _repeats(repeats), _printPartialData(printPartialData), _simType("none") {} 15 | 16 | void makeStandard(size_t varCount, size_t inserts, size_t queries, bool findAll); 17 | 18 | template 19 | void run(); 20 | template 21 | void run(const Param1& param1); 22 | template 23 | void run(const Param1& param1, const Param2& param2); 24 | template 25 | void run(const Param1& param1, const Param2& param2, const Param3& param3); 26 | template 27 | void run(const P1& p1, const P2& p2, const P3& param3, const P4& param4); 28 | template 29 | void run(const P1& p1, const P2& p2, const P3& param3, const P4& param4, 30 | const P5& p5); 31 | template 33 | void run(const P1& p1, const P2& p2, const P3& param3, const P4& param4, 34 | const P5& p5, const P6& p6); 35 | 36 | void printData(std::ostream& out) const; 37 | 38 | private: 39 | struct SimData { 40 | bool operator<(const SimData& sd) const; 41 | void print(std::ostream& out); 42 | 43 | std::string _name; 44 | unsigned long _mseconds; 45 | unsigned long long _expQueryCount; 46 | }; 47 | 48 | template 49 | void run(DivFinder& finder); 50 | 51 | enum EventType { 52 | InsertUnknown, 53 | InsertKnown, 54 | QueryNoDivisor, 55 | QueryHasDivisor, 56 | QueryUnknown, 57 | StateUnknown, 58 | StateKnown 59 | }; 60 | struct Event { 61 | EventType _type; 62 | std::vector _monomial; 63 | std::vector _state; 64 | #ifdef DEBUG 65 | std::vector _allMonomials; 66 | #else 67 | size_t _monomialCount; 68 | #endif 69 | }; 70 | class MonomialStore; 71 | 72 | bool _findAll; 73 | std::vector _events; 74 | std::vector _data; 75 | size_t _varCount; 76 | size_t _repeats; 77 | bool _printPartialData; 78 | std::string _simType; 79 | }; 80 | 81 | template 82 | void Simulation::run() { 83 | DivFinder finder(_varCount); 84 | run(finder); 85 | } 86 | 87 | template 88 | void Simulation::run(const Param1& param1) { 89 | DivFinder finder(_varCount, param1); 90 | run(finder); 91 | } 92 | 93 | template 94 | void Simulation::run(const Param1& param1, const Param2& param2) { 95 | DivFinder finder(_varCount, param1, param2); 96 | run(finder); 97 | } 98 | 99 | template 100 | void Simulation::run 101 | (const Param1& param1, const Param2& param2, const Param3& param3) { 102 | DivFinder finder(_varCount, param1, param2, param3); 103 | run(finder); 104 | } 105 | 106 | template 107 | void Simulation::run 108 | (const P1& param1, const P2& param2, const P3& param3, const P4& param4) { 109 | DivFinder finder(_varCount, param1, param2, param3, param4); 110 | run(finder); 111 | } 112 | 113 | template 114 | void Simulation::run 115 | (const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5) { 116 | DivFinder finder(_varCount, p1, p2, p3, p4, p5); 117 | run(finder); 118 | } 119 | 120 | template 122 | void Simulation::run 123 | (const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, 124 | const P6& p6) { 125 | DivFinder finder(_varCount, p1, p2, p3, p4, p5, p6); 126 | run(finder); 127 | } 128 | 129 | class Simulation::MonomialStore { 130 | public: 131 | MonomialStore() {clear();} 132 | void clear() { 133 | #ifdef DEBUG 134 | _monomials.clear(); 135 | #else 136 | _monomialCount = 0; 137 | #endif 138 | } 139 | 140 | void push_back(const Monomial& monomial) { 141 | proceed(monomial); 142 | } 143 | bool proceed(const Monomial& monomial) { 144 | #ifdef DEBUG 145 | _monomials.push_back(monomial); 146 | #else 147 | ++_monomialCount; 148 | #endif 149 | return true; 150 | } 151 | 152 | template 153 | void checkInsert(Event& e, const Finder& finder) { 154 | #ifdef DEBUG 155 | std::sort(_monomials.begin(), _monomials.end()); 156 | #endif 157 | 158 | if (e._type == InsertUnknown) { 159 | #ifdef DEBUG 160 | e._allMonomials.clear(); 161 | for (size_t i = 0; i < _monomials.size(); ++i) 162 | e._allMonomials.push_back(_monomials[i]); 163 | #else 164 | e._monomialCount = _monomialCount; 165 | #endif 166 | e._type = InsertKnown; 167 | } else { 168 | #ifdef DEBUG 169 | ASSERT(_monomials == e._allMonomials); 170 | #else 171 | if (_monomialCount != e._monomialCount) { 172 | std::cerr << "Finder \"" << finder.getName() << 173 | "\" found incorrect number of monomials." << std::endl; 174 | std::exit(1); 175 | } 176 | #endif 177 | } 178 | } 179 | 180 | template 181 | void checkQuery(Event& e, const Finder& finder) { 182 | #ifdef DEBUG 183 | for (size_t d = 0; d < _monomials.size(); ++d) { 184 | for (size_t var = 0; var < e._monomial.size(); ++var) { 185 | ASSERT(_monomials[d][var] <= e._monomial[var]); 186 | } 187 | } 188 | std::sort(_monomials.begin(), _monomials.end()); 189 | #endif 190 | 191 | if (e._type == QueryUnknown) { 192 | bool noMonomials; 193 | #ifdef DEBUG 194 | e._allMonomials.clear(); 195 | for (size_t i = 0; i < _monomials.size(); ++i) 196 | e._allMonomials.push_back(_monomials[i]); 197 | noMonomials = _monomials.empty(); 198 | #else 199 | e._monomialCount = _monomialCount; 200 | noMonomials = _monomialCount == 0; 201 | #endif 202 | e._type = noMonomials ? QueryNoDivisor : QueryHasDivisor; 203 | } else { 204 | #ifdef DEBUG 205 | for (size_t i = 0; i < _monomials.size(); ++i) 206 | ASSERT(_monomials[i] == e._allMonomials[i]); 207 | #else 208 | if (_monomialCount != e._monomialCount) { 209 | std::cerr << "Finder \"" << finder.getName() << 210 | "\" found incorrect number of monomials." << std::endl; 211 | std::exit(1); 212 | } 213 | #endif 214 | } 215 | } 216 | 217 | private: 218 | #ifdef DEBUG 219 | std::vector _monomials; 220 | #else 221 | size_t _monomialCount; 222 | #endif 223 | }; 224 | 225 | struct ForAll { 226 | public: 227 | ForAll(std::vector& entries): _entries(entries) {} 228 | bool proceed(const Monomial& m) { 229 | _entries.push_back(m.getPointer()); 230 | return true; 231 | } 232 | 233 | private: 234 | std::vector& _entries; 235 | }; 236 | 237 | template 238 | void Simulation::run(DivFinder& finder) { 239 | mic::Timer timer; 240 | std::vector divisors; 241 | std::vector tmp; 242 | for (size_t step = 0; step < _repeats; ++step) { 243 | for (size_t i = 0; i < _events.size(); ++i) { 244 | Event& e = _events[i]; 245 | if (e._type == InsertKnown || e._type == InsertUnknown) { 246 | divisors.clear(); 247 | MonomialStore store; 248 | if (0) { 249 | // here to make sure it compiles, also easy to switch to checking this instead. 250 | finder.insert(e._monomial); 251 | } else 252 | finder.insert(e._monomial, store); 253 | store.checkInsert(e, finder); 254 | } else if (e._type == StateUnknown || e._type == StateKnown) { 255 | tmp.clear(); 256 | ForAll forAll(tmp); 257 | finder.forAll(forAll); 258 | if (e._type == StateUnknown) { 259 | e._type = StateKnown; 260 | e._state.swap(tmp); 261 | } else { 262 | if (e._state != tmp) { 263 | std::cerr << "states differ." << std::endl; 264 | std::exit(1); 265 | } 266 | } 267 | } else if (!_findAll) { 268 | typename DivFinder::Entry* entry = finder.findDivisor(e._monomial); 269 | if (entry == 0) { 270 | if (e._type == QueryHasDivisor) { 271 | std::cerr << "Divisor finder \"" << finder.getName() 272 | << "\" failed to find divisor." << std::endl; 273 | std::exit(1); 274 | } 275 | e._type = QueryNoDivisor; 276 | } else { 277 | #ifdef DEBUG 278 | for (size_t var = 0; var < _varCount; ++var) { 279 | ASSERT((*entry)[var] <= e._monomial[var]); 280 | } 281 | #endif 282 | if (e._type == QueryNoDivisor) { 283 | std::cerr << "Divisor finder \"" << finder.getName() << 284 | "\" found incorrect divisor." << std::endl; 285 | std::exit(1); 286 | } 287 | e._type = QueryHasDivisor; 288 | } 289 | } else { 290 | ASSERT(_findAll); 291 | divisors.clear(); 292 | MonomialStore store; 293 | const_cast(finder) // to test const interface 294 | .findAllDivisors(e._monomial, store); 295 | store.checkQuery(e, finder); 296 | } 297 | } 298 | } 299 | 300 | SimData data; 301 | data._mseconds = (unsigned long)timer.getMilliseconds(); 302 | data._name = finder.getName(); 303 | data._expQueryCount = finder.getExpQueryCount(); 304 | _data.push_back(data); 305 | if (_printPartialData) 306 | data.print(std::cerr); 307 | std::cout << finder.size() << std::endl; 308 | } 309 | 310 | #endif 311 | -------------------------------------------------------------------------------- /src/divsim/divMain.cpp: -------------------------------------------------------------------------------- 1 | #include "stdinc.h" 2 | 3 | #include "DivListModel.h" 4 | #include "KDTreeModel.h" 5 | #include "Simulation.h" 6 | #include "mathic/Timer.h" 7 | #include 8 | 9 | int main() { 10 | const size_t repeats = IF_DEBUG(true ? 1 :) 1; 11 | Simulation sim(repeats, true); 12 | mic::Timer timer; 13 | std::cout << "Generating simulation. "; 14 | 15 | 16 | #ifdef DEBUG 17 | sim.makeStandard(10, 400, 1000, true); 18 | #else 19 | sim.makeStandard(10, 5000, 2000000, true); 20 | #endif 21 | timer.print(std::cout); 22 | std::cout << std::endl; 23 | 24 | #ifndef DEBUG 25 | sim.run >(0, 0, 0, 1.0, 1000); 26 | sim.run >(0, 0, 0, 1.0, 1000); 27 | return 0; 28 | 29 | sim.run >(1, 0, 0, 0.0, 0); // best tree, no mask 30 | sim.run >(1, 0, 0, 0.0, 0); // best tree, no mask 31 | 32 | sim.run >(1, 0, 0, 1.0, 1000); // best tree, mask 33 | sim.run >(1, 0, 0, 1.0, 1000); // best tree, mask 34 | 35 | sim.run >(1, 1, 0, 0.5, 500); 36 | return 0; 37 | #endif 38 | 39 | 40 | /* 41 | for (int minimizeOnInsert = 1; minimizeOnInsert <= 1; ++minimizeOnInsert) { 42 | for (int order = 0; order <= 2; ++order) { 43 | bool moveDivisorToFront = (order == 1); 44 | bool sortOnInsert = (order == 2); 45 | sim.run > 46 | (minimizeOnInsert, moveDivisorToFront, sortOnInsert); 47 | sim.run > 48 | (minimizeOnInsert, moveDivisorToFront, sortOnInsert); 49 | } 50 | } 51 | //*/ 52 | 53 | //sim.run >(1, 0, 1, 0.0, 0); // best array, no mask 54 | /* 55 | sim.run >(1, 0, 0) 56 | sim.run >(1, 1, 0); 57 | sim.run >(1, 0, 1); 58 | sim.run >(1, 0, 0); 59 | sim.run >(1, 1, 0); 60 | sim.run >(1, 0, 1); 61 | //*/ 62 | 63 | sim.run >(0, 0, 0, 0.0, 0); 64 | sim.run >(0, 1, 0, 0.5, 500); 65 | for (int mini = 0; mini <= 0; ++mini) { 66 | for (int sortOnInsert = 0; sortOnInsert <= 1; ++sortOnInsert) { 67 | for (int useDivCache = 0; useDivCache <= 1; ++useDivCache) { 68 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 69 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 70 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 71 | 72 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 73 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 74 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 75 | 76 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 77 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 78 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 79 | 80 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 81 | 82 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 83 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 84 | sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); 85 | 86 | /* 87 | for (size_t leafSize = 5; leafSize <= 15; leafSize += 5) 88 | for (size_t start = 0; start <= 0; start += 200) 89 | for (double ratio = 0; ratio < 0.1; ratio += 0.2) 90 | sim.run >(leafSize, mini,sortOnInsert,useDivisorCache, ratio, start); 91 | 92 | //*/ 93 | /*sim.run >(8, mini,sortOnInsert,useDivisorCache, 0, 0); 94 | sim.run >(8, mini,sortOnInsert,useDivisorCache, 0, 0); 95 | sim.run >(20, mini,sortOnInsert,useDivisorCache, 0, 0); 96 | sim.run >(20, mini,sortOnInsert,useDivisorCache, 0, 0); 97 | sim.run >(40, mini,sortOnInsert,useDivisorCache, 0, 0); 98 | sim.run >(40, mini,sortOnInsert,useDivisorCache, 0, 0); 99 | sim.run >(60, mini,sortOnInsert,useDivisorCache, 0, 0); 100 | sim.run >(60, mini,sortOnInsert,useDivisorCache, 0, 0);*/ 101 | 102 | /* 103 | sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 2000); 104 | sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 4000); 105 | 106 | sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 6000); 107 | sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 6000); 108 | 109 | sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 8000); 110 | sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 10000);*/ 111 | //sim.run(10, mini,sortOnInsert,useDivisorCache, 4, 2000); 112 | //sim.run(20, mini,sortOnInsert,useDivisorCache, 0.75, 2000); 113 | //sim.run(8, mini,sortOnInsert,useDivisorCache, 0.75, 2000); 114 | } 115 | } 116 | } 117 | //*/ 118 | /* 119 | for (int mini = 1; mini <= 1; ++mini) { 120 | for (int noneFrontSort = 0; noneFrontSort <= 2; ++noneFrontSort) { 121 | bool tof = (noneFrontSort == 1); 122 | bool sort = (noneFrontSort == 2); 123 | 124 | for (double ratio = 0.5; ratio < 0.51; ratio += 0.1) 125 | for (size_t start = 500; start <= 500; start += 100) 126 | sim.run >(mini, tof, sort, ratio, start); 127 | } 128 | } 129 | //*/ 130 | 131 | /* best for single query from best to worst 132 | sim.run >(40, 1, 0, 0, 1.0, 1000); // best tree, mask 133 | sim.run >(15, 1, 0, 0, 0.0, 0); // best tree, no mask 134 | sim.run >(1, 1, 0, 0.5, 500); // best array, mask 135 | sim.run >(1, 1, 0, 0.5, 500); // should be best linked, mask 136 | sim.run >(1, 0, 1, 0.0, 0); // best array, no mask 137 | sim.run >(1, 0, 1, 0.0, 0); // best linked, no mask 138 | //*/ 139 | 140 | /* base div lists 141 | sim.run >(1, 0, 0, 0.0, 0); // base array 142 | sim.run >(1, 0, 0, 0.0, 0); // base linked 143 | //*/ 144 | 145 | std::cout << "\n\n"; 146 | sim.printData(std::cout); 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /src/divsim/divMain.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_DIV_MAIN_GUARD 2 | #define MATHIC_DIV_MAIN_GUARD 3 | 4 | int main(); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/divsim/stdinc.h: -------------------------------------------------------------------------------- 1 | #ifdef STDINC_GUARD 2 | #error stdinc.h included twice 3 | #endif 4 | #define STDINC_GUARD 5 | 6 | #ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++. 7 | #pragma warning (push, 1) // Reduce warning level for GMP headers. 8 | #endif 9 | 10 | #ifdef PROFILE 11 | #define NO_PINLINE NO_INLINE 12 | #else 13 | #define NO_PINLINE 14 | #endif 15 | 16 | #ifndef _MSC_VER 17 | #define NO_INLINE __attribute__ ((noinline)) 18 | #endif 19 | 20 | #ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++. 21 | #define NO_INLINE __declspec(noinline) 22 | #pragma warning (pop) // Go back to previous warning level. 23 | #pragma warning (disable: 4996) // std::copy is flagged as dangerous. 24 | #pragma warning (disable: 4290) // VC++ ignores throw () specification. 25 | #pragma warning (disable: 4127) // Warns about using "while (true)". 26 | #pragma warning (disable: 4100) // Warns about unused parameters. 27 | #pragma warning (disable: 4800) // Warns on int to bool conversion. 28 | #pragma warning (disable: 4146) // Warns on unary minus on unsigned (bit trick) 29 | 30 | // This warning warns about using the this pointer in base member 31 | // initializer lists. This is a pretty good warning as that can 32 | // obviously easily go wrong, but it is pretty useful to do as well, 33 | // so the warning is turned off. 34 | #pragma warning (disable: 4355) 35 | 36 | #ifdef _DEBUG 37 | #define DEBUG 38 | #endif 39 | 40 | #endif 41 | 42 | #include 43 | #include 44 | 45 | #ifdef DEBUG 46 | #include // Useful for debugging. 47 | #define PRINT 48 | #include 49 | #define ASSERT(X) assert(X); 50 | #define IF_DEBUG(X) X 51 | #else 52 | #define ASSERT(X) 53 | #define IF_DEBUG(X) 54 | #endif 55 | 56 | static const size_t BitsPerByte = 8; 57 | static const size_t MemoryAlignment = sizeof(void*); 58 | -------------------------------------------------------------------------------- /src/mathic.cpp: -------------------------------------------------------------------------------- 1 | #include "mathic.h" 2 | 3 | extern "C" { 4 | void libmathicIsPresent(void) {} 5 | } 6 | -------------------------------------------------------------------------------- /src/mathic.h: -------------------------------------------------------------------------------- 1 | // Include this file to pull in all external Mathic files 2 | 3 | // utilities 4 | #include "mathic/Timer.h" 5 | #include "mathic/ColumnPrinter.h" 6 | #include "mathic/error.h" 7 | 8 | // other data structures 9 | #include "mathic/BitTriangle.h" 10 | #include "mathic/HashTable.h" 11 | 12 | // divisor query data structures 13 | #include "mathic/DivList.h" 14 | #include "mathic/KDTree.h" 15 | 16 | // priority queue data structures 17 | #include "mathic/TourTree.h" 18 | #include "mathic/StlSet.h" 19 | #include "mathic/Heap.h" 20 | #include "mathic/Geobucket.h" 21 | #include "mathic/PairQueue.h" 22 | 23 | // CLI package 24 | #include "mathic/Action.h" 25 | #include "mathic/BoolParameter.h" 26 | #include "mathic/CliParameter.h" 27 | #include "mathic/CliParser.h" 28 | #include "mathic/HelpAction.h" 29 | #include "mathic/IntegerParameter.h" 30 | #include "mathic/StringParameter.h" 31 | #include "mathic/display.h" 32 | 33 | extern "C" { 34 | // Put a C function in the library so that it can be detected by the autoconf 35 | // macro AC_CHECK_LIB. That macro can only check for libraries that contain 36 | // at least one C function. 37 | void libmathicIsPresent(void); // This function does nothing. 38 | } 39 | -------------------------------------------------------------------------------- /src/mathic/Action.cpp: -------------------------------------------------------------------------------- 1 | #include "Action.h" 2 | #include "error.h" 3 | 4 | namespace mathic { 5 | Action::~Action() { 6 | } 7 | 8 | void Action::directOptions( 9 | std::vector tokens, 10 | CliParser& parser 11 | ) { 12 | if (!tokens.empty()) { 13 | reportError("Expected a dash (-) to indicate an option when reading \"" + 14 | tokens.front() + "\"."); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/mathic/Action.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_ACTION_GUARD 2 | #define MATHIC_ACTION_GUARD 3 | 4 | #include "stdinc.h" 5 | #include 6 | #include 7 | 8 | namespace mathic { 9 | class CliParameter; 10 | class CliParser; 11 | 12 | class Action { 13 | public: 14 | virtual ~Action(); 15 | 16 | // Called with tokens that precede any option of the 17 | // form -option. The default is to give an error saying 18 | // that a dash was expected if tokens is not empty. 19 | virtual void directOptions 20 | (std::vector tokens, CliParser& parser); 21 | 22 | // Do what it is this action does. 23 | virtual void performAction() = 0; 24 | 25 | // *************************************** 26 | // **** Information provided by each Action 27 | 28 | // The name of the action. 29 | virtual const char* name() const = 0; 30 | 31 | // More detailed explanation of what the action does. 32 | virtual const char* description() const = 0; 33 | 34 | // One-line summary of the description. 35 | virtual const char* shortDescription() const = 0; 36 | 37 | // Append the parameters for this action to the passed-in container. 38 | // Do not clear the passed-in container. 39 | virtual void pushBackParameters(std::vector& parameters) = 0; 40 | 41 | // Return true if this class is HelpAction. 42 | virtual bool isHelpAction() const {return false;} 43 | }; 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/mathic/BitTriangle.cpp: -------------------------------------------------------------------------------- 1 | #include "stdinc.h" 2 | #include "BitTriangle.h" 3 | 4 | namespace mathic { 5 | size_t BitTriangle::getMemoryUse() const 6 | { 7 | size_t sum = mColumns.capacity() * sizeof(mColumns.front()); 8 | const size_t stop = mColumns.size(); 9 | for (size_t i = 0; i != stop; ++i) { 10 | size_t const capacity = mColumns[i].capacity(); 11 | sum += (capacity + 7) / 8; // 8 bits per byte rounded up 12 | } 13 | return sum; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/mathic/BitTriangle.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_BIT_TRIANGLE_GUARD 2 | #define MATHIC_BIT_TRIANGLE_GUARD 3 | 4 | #include "stdinc.h" 5 | #include 6 | #include 7 | 8 | namespace mathic { 9 | // Object that stores a triangular 2-dimensional array of bits. For example: 10 | // 11 | // row 12 | // 3| 13 | // 2| 1 14 | // 1| 0 1 15 | // 0| 0 0 0 16 | // ------- 17 | // 0 1 2 3 column 18 | // 19 | // A bit is addressed by a pair (column, row) where the column goes first. 20 | // All valid address pairs have 0 <= row < column < columnCount(). 21 | // Columns can be added dynamically. 22 | class BitTriangle { 23 | public: 24 | // Returns how many columns the triangle has 25 | size_t columnCount() const {return mColumns.size();} 26 | 27 | // Returns true if there are no columns in the triangle 28 | bool empty() const {return mColumns.empty();} 29 | 30 | // Adds a new column of the triangle. This increases columnCount() by 31 | // one, and the index of the new column is the previous value of 32 | // columnCount(). The new bits are all set to false initially. 33 | void addColumn() { 34 | size_t const oldSize = mColumns.size(); 35 | mColumns.resize(oldSize + 1); 36 | mColumns[oldSize].resize(oldSize); 37 | } 38 | 39 | // Returns the bit in the given column and row. As this is a triangle it 40 | // must be true that row < column. 41 | MATHIC_INLINE bool bit(size_t column, size_t row) const { 42 | MATHIC_ASSERT(column < columnCount()); 43 | MATHIC_ASSERT(row < column); 44 | return mColumns[column][row]; 45 | } 46 | 47 | // As bit(), but uses max(x,y) as the column and min(x,y) as the 48 | // row. 49 | bool bitUnordered(size_t x, size_t y) const { 50 | MATHIC_ASSERT(x < columnCount()); 51 | MATHIC_ASSERT(y < columnCount()); 52 | MATHIC_ASSERT(x != y); 53 | if (x < y) 54 | std::swap(x, y); 55 | return bit(x, y); 56 | } 57 | 58 | // Sets the bit in the given column and row. As this is a triangle 59 | // it must be true that column >= row. 60 | MATHIC_INLINE void setBit(size_t column, size_t row, bool value) { 61 | MATHIC_ASSERT(column < columnCount()); 62 | MATHIC_ASSERT(row < column); 63 | mColumns[column][row] = value; 64 | } 65 | 66 | // As setBit, but uses max(x,y) as the column and min(x,y) as the 67 | // row. 68 | void setBitUnordered(size_t x, size_t y, bool value) { 69 | MATHIC_ASSERT(x < columnCount()); 70 | MATHIC_ASSERT(y < columnCount()); 71 | MATHIC_ASSERT(x != y); 72 | if (x < y) 73 | std::swap(x, y); 74 | setBit(x, y, value); 75 | } 76 | 77 | size_t getMemoryUse() const; 78 | 79 | private: 80 | // @todo: use one big array instead of an array of arrays. 81 | std::vector > mColumns; 82 | }; 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/mathic/BoolParameter.cpp: -------------------------------------------------------------------------------- 1 | #include "BoolParameter.h" 2 | 3 | #include "error.h" 4 | 5 | namespace mathic { 6 | BoolParameter::BoolParameter(const std::string& name, 7 | const std::string& description, 8 | bool defaultValue): 9 | CliParameter(name, description), 10 | _value(defaultValue) { 11 | } 12 | 13 | std::string BoolParameter::argumentType() const { 14 | return "[BOOL]"; 15 | } 16 | 17 | std::string BoolParameter::valueAsString() const { 18 | return _value ? "on" : "off"; 19 | } 20 | 21 | void BoolParameter::processArgument(const std::string& argument) { 22 | if (argument.empty() || argument == "on") 23 | _value = true; 24 | else if (argument == "off") 25 | _value = false; 26 | else { 27 | reportError("Option -" + name() + " was given the argument \"" + 28 | argument + "\". The only valid arguments are \"on\" and \"off\"."); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/mathic/BoolParameter.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_BOOL_PARAMETER_GUARD 2 | #define MATHIC_BOOL_PARAMETER_GUARD 3 | 4 | #include "stdinc.h" 5 | #include "CliParameter.h" 6 | #include 7 | #include 8 | 9 | namespace mathic { 10 | class BoolParameter : public CliParameter { 11 | public: 12 | BoolParameter(const std::string& name, 13 | const std::string& description, 14 | bool defaultValue); 15 | 16 | bool value() const {return _value;} 17 | void setValue(bool value) {_value = value;} 18 | 19 | operator bool() const {return value();} 20 | void operator=(bool value) {setValue(value);} 21 | 22 | virtual std::string argumentType() const; 23 | virtual std::string valueAsString() const; 24 | virtual void processArgument(const std::string& argument); 25 | 26 | private: 27 | bool _value; 28 | }; 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/mathic/CliParameter.cpp: -------------------------------------------------------------------------------- 1 | #include "CliParameter.h" 2 | #include "error.h" 3 | 4 | namespace mathic { 5 | CliParameter::CliParameter( 6 | const std::string& name, 7 | const std::string& description 8 | ): 9 | _name(name), 10 | _description(description) { 11 | } 12 | 13 | CliParameter::~CliParameter() { 14 | } 15 | 16 | void CliParameter::appendToDescription(const std::string& str) { 17 | _description += str; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/mathic/CliParameter.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_PARAMETER_GUARD 2 | #define MATHIC_PARAMETER_GUARD 3 | 4 | #include "stdinc.h" 5 | #include 6 | 7 | namespace mathic { 8 | class CliParameter { 9 | public: 10 | virtual ~CliParameter(); 11 | 12 | const std::string& name() const {return _name;} 13 | const std::string& description() const {return _description;} 14 | void appendToDescription(const std::string& str); 15 | 16 | virtual std::string argumentType() const = 0; 17 | virtual std::string valueAsString() const = 0; 18 | virtual void processArgument(const std::string& argument) = 0; 19 | 20 | protected: 21 | CliParameter(const std::string& name, const std::string& description); 22 | 23 | private: 24 | std::string _name; 25 | std::string _description; 26 | }; 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/mathic/CliParser.cpp: -------------------------------------------------------------------------------- 1 | #include "CliParser.h" 2 | 3 | #include "error.h" 4 | #include "CliParameter.h" 5 | 6 | namespace mathic { 7 | namespace { 8 | // We are using a NameFactory just for its prefix-finding functionality, so 9 | // we set the thing being created to be just void pointers that are null. 10 | typedef void* Dummy; 11 | typedef NameFactory ParamNames; 12 | ParamNames makeParamNames(std::vector params) { 13 | ParamNames names("option"); 14 | for (size_t i = 0; i < params.size(); ++i) { 15 | const auto makeNull = [](){return std::unique_ptr();}; 16 | names.registerProduct(params[i]->name(), makeNull); 17 | } 18 | return names; 19 | } 20 | } 21 | 22 | void CliParser::pushBackRegisteredActionNames( 23 | std::vector& names 24 | ) const { 25 | _actions.namesWithPrefix("", names); 26 | } 27 | 28 | 29 | CliParser::CliParser(): _actions("action") {} 30 | 31 | std::unique_ptr CliParser::createActionWithPrefix( 32 | const std::string& prefix 33 | ) { 34 | return createWithPrefix(_actions, prefix); 35 | } 36 | 37 | std::unique_ptr CliParser::parse(int argc, char** argv) { 38 | std::vector commandLine(argv, argv + argc); 39 | return parse(commandLine); 40 | } 41 | 42 | std::unique_ptr CliParser::parse 43 | (const std::vector& commandLine) { 44 | if (commandLine.empty()) 45 | throwError("No action specified."); 46 | std::unique_ptr action = createActionWithPrefix(commandLine[0]); 47 | 48 | std::vector params; 49 | action->pushBackParameters(params); 50 | ParamNames paramNames = makeParamNames(params); 51 | 52 | std::vector options; 53 | std::vector directOptions; 54 | bool sawDash = false; 55 | for (size_t i = 1; i < commandLine.size(); ++i) { 56 | if (commandLine[i].empty()) 57 | continue; 58 | if (commandLine[i][0] == '-') 59 | sawDash = true; 60 | if (sawDash) 61 | options.push_back(commandLine[i]); 62 | else 63 | directOptions.push_back(commandLine[i]); 64 | } 65 | 66 | action->directOptions(directOptions, *this); 67 | 68 | size_t i = 1; 69 | for (size_t i = 0; i < options.size(); ++i) { 70 | std::string const& token = options[i]; 71 | if (token[0] != '-') 72 | reportError("Expected an option when reading \"" + 73 | token + "\", but options start with a dash (-).\n"); 74 | std::string noDash(token.begin() + 1, token.end()); 75 | std::string name = uniqueNameWithPrefix(paramNames, noDash); 76 | 77 | std::string optionArgument; 78 | if (i + 1 < options.size() && options[i + 1][0] != '-') { 79 | optionArgument = options[i + 1]; 80 | ++i; 81 | } 82 | 83 | for (std::vector::iterator it = params.begin();; ++it) { 84 | if (it == params.end()) { 85 | // shouldn't get here as name was recognized above 86 | reportInternalError("Processing non-existent option \"" 87 | + name + "\"."); 88 | } 89 | if ((*it)->name() == name) { 90 | (*it)->processArgument(optionArgument); 91 | break; 92 | } 93 | } 94 | } 95 | return action; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/mathic/CliParser.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_CLI_PARSER_GUARD 2 | #define MATHIC_CLI_PARSER_GUARD 3 | 4 | #include "NameFactory.h" 5 | #include "Action.h" 6 | 7 | namespace mathic { 8 | class CliParser { 9 | public: 10 | CliParser(); 11 | 12 | template 13 | void registerAction(const std::string& name); 14 | 15 | // picks the name up from ConcreteAction::staticName(). 16 | template 17 | void registerAction(); 18 | 19 | void registerHelpAction 20 | (const std::string& preMessage, const std::string& postMessage); 21 | 22 | void pushBackRegisteredActionNames( 23 | std::vector& names 24 | ) const; 25 | 26 | const std::string& helpPreMessage() const {return _helpPreMessage;} 27 | const std::string& helpPostMessage() const {return _helpPostMessage;} 28 | 29 | std::unique_ptr parse(int argc, char** argv); 30 | std::unique_ptr parse(const std::vector& commandLine); 31 | std::unique_ptr createActionWithPrefix(const std::string& prefix); 32 | 33 | private: 34 | NameFactory _actions; 35 | std::string _helpPreMessage; 36 | std::string _helpPostMessage; 37 | }; 38 | 39 | template 40 | void CliParser::registerAction(const std::string& name) { 41 | nameFactoryRegister(_actions, name); 42 | }; 43 | 44 | template 45 | void CliParser::registerAction() { 46 | nameFactoryRegister(_actions); 47 | }; 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/mathic/ColumnPrinter.cpp: -------------------------------------------------------------------------------- 1 | #include "ColumnPrinter.h" 2 | 3 | namespace mathic { 4 | namespace { 5 | size_t getLineWidth(const std::string& str, size_t pos) { 6 | size_t startPos = pos; 7 | while (pos < str.size() && str[pos] != '\n' && str[pos] != '\0') 8 | ++pos; 9 | return pos - startPos; 10 | } 11 | 12 | void printChars(std::ostream& out, size_t howMany, const char c) { 13 | while (howMany > 0) { 14 | out << c; 15 | --howMany; 16 | } 17 | } 18 | } 19 | 20 | ColumnPrinter::ColumnPrinter(size_t columnCount): 21 | _cols() { 22 | while (columnCount > 0) { 23 | addColumn(); 24 | --columnCount; 25 | } 26 | } 27 | 28 | void ColumnPrinter::setPrefix(const std::string& prefix) { 29 | _prefix = prefix; 30 | } 31 | 32 | std::ostream& ColumnPrinter::addColumn(bool flushLeft, 33 | const std::string& prefix, 34 | const std::string& suffix) { 35 | std::unique_ptr col(new Col()); 36 | col->prefix = prefix; 37 | col->suffix = suffix; 38 | col->flushLeft = flushLeft; 39 | 40 | _cols.emplace_back(std::move(col)); 41 | 42 | return _cols.back()->text; 43 | } 44 | 45 | size_t ColumnPrinter::getColumnCount() const { 46 | return _cols.size(); 47 | } 48 | 49 | std::ostream& ColumnPrinter::operator[](size_t col) { 50 | MATHIC_ASSERT(col < getColumnCount()); 51 | return _cols[col]->text; 52 | } 53 | 54 | void ColumnPrinter::repeatToEndOfLine(const char repeatThis, size_t col) { 55 | MATHIC_ASSERT(col < getColumnCount()); 56 | (*this)[col] << '\0' << repeatThis; 57 | } 58 | 59 | void ColumnPrinter::repeatToEndOfLine(const char repeatThis) { 60 | MATHIC_ASSERT(repeatThis != '\n'); 61 | for (size_t col = 0; col < getColumnCount(); ++col) 62 | repeatToEndOfLine(repeatThis, col); 63 | } 64 | 65 | void ColumnPrinter::print(std::ostream& out) const { 66 | // stringstream::str() copies the string, so we need 67 | // to extract all the strings and store them to avoid copying 68 | // at every access. 69 | std::vector texts(getColumnCount()); 70 | for (size_t col = 0; col < getColumnCount(); ++col) 71 | texts[col] = _cols[col]->text.str(); 72 | 73 | // Calculate the width of each column. 74 | std::vector widths(getColumnCount()); 75 | for (size_t col = 0; col < getColumnCount(); ++col) { 76 | const auto& text = texts[col]; 77 | size_t maxWidth = 0; 78 | 79 | size_t pos = 0; 80 | while (pos < text.size()) { 81 | size_t width = getLineWidth(text, pos); 82 | if (width > maxWidth) 83 | maxWidth = width; 84 | 85 | // We can't just increment pos unconditionally by width + 1, as 86 | // that could result in an overflow. 87 | pos += width; 88 | if (pos == text.size()) 89 | break; 90 | if (text[pos] == '\0') { 91 | ++pos; 92 | if (pos == text.size()) 93 | break; 94 | ++pos; 95 | } else if (text[pos] == '\n') 96 | ++pos; 97 | } 98 | widths[col] = maxWidth; 99 | } 100 | 101 | // Print each row 102 | std::vector poses(getColumnCount()); 103 | while (true) { 104 | bool done = true; 105 | for (size_t col = 0; col < getColumnCount(); ++col) { 106 | if (poses[col] < texts[col].size()) { 107 | done = false; 108 | break; 109 | } 110 | } 111 | if (done) 112 | break; 113 | 114 | out << _prefix; 115 | for (size_t col = 0; col < getColumnCount(); ++col) { 116 | out << _cols[col]->prefix; 117 | 118 | const std::string& text = texts[col]; 119 | size_t& pos = poses[col]; 120 | size_t width = getLineWidth(text, pos); 121 | 122 | char padChar = ' '; 123 | if ( 124 | pos + width < text.size() && 125 | text[pos + width] == '\0' && 126 | pos + width + 1 < text.size() 127 | ) { 128 | padChar = text[pos + width + 1]; 129 | } 130 | 131 | if (!_cols[col]->flushLeft) 132 | printChars(out, widths[col] - width, padChar); 133 | 134 | while (pos < text.size()) { 135 | if (text[pos] == '\n') { 136 | ++pos; 137 | break; 138 | } 139 | if (text[pos] == '\0') { 140 | ++pos; 141 | if (pos < text.size()) { 142 | MATHIC_ASSERT(text[pos] == padChar); 143 | ++pos; 144 | } 145 | break; 146 | } 147 | out << text[pos]; 148 | ++pos; 149 | } 150 | 151 | if (_cols[col]->flushLeft) 152 | printChars(out, widths[col] - width, padChar); 153 | 154 | out << _cols[col]->suffix; 155 | } 156 | out << '\n'; 157 | } 158 | } 159 | 160 | std::string ColumnPrinter::commafy(const unsigned long long l) { 161 | std::stringstream out; 162 | out << l; 163 | const auto uncomma = out.str(); 164 | std::string str; 165 | for (size_t i = 0; i < uncomma.size(); ++i) { 166 | str += uncomma[i]; 167 | if (i != uncomma.size() - 1 && ((uncomma.size() - i) % 3) == 1) 168 | str += ','; 169 | } 170 | return str; 171 | } 172 | 173 | std::string ColumnPrinter::percentInteger( 174 | const unsigned long long numerator, 175 | const unsigned long long denominator 176 | ) { 177 | return ratioInteger(numerator * 100, denominator) + '%'; 178 | } 179 | 180 | std::string ColumnPrinter::percentDouble( 181 | const double numerator, 182 | const double denominator 183 | ) { 184 | return ratioDouble(numerator * 100, denominator) + '%'; 185 | } 186 | 187 | std::string ColumnPrinter::percentIntegerFixed( 188 | const unsigned long long numerator, 189 | const unsigned long long denominator 190 | ) { 191 | auto str = percentInteger(numerator, denominator); 192 | const size_t maxSize = 6; 193 | MATHIC_ASSERT(maxSize == std::string("100.0%").size()); 194 | const auto size = str.size(); 195 | if (size > maxSize) 196 | return std::move(str); 197 | return std::string(maxSize - str.size(), ' ') + std::move(str); 198 | } 199 | 200 | std::string ColumnPrinter::percentDouble(const double ratio) { 201 | return oneDecimal(ratio * 100) + '%'; 202 | } 203 | 204 | std::string ColumnPrinter::ratioInteger( 205 | const unsigned long long numerator, 206 | const unsigned long long denominator 207 | ) { 208 | if (denominator == 0) 209 | return std::string(numerator == 0 ? "0/0" : "?/0"); 210 | return oneDecimal(static_cast(numerator) / denominator); 211 | } 212 | 213 | std::string ColumnPrinter::ratioDouble( 214 | const double numerator, 215 | const double denominator 216 | ) { 217 | const auto epsilon = 0.000000001; 218 | if (-epsilon < denominator && denominator < epsilon) { 219 | if (-epsilon < numerator && numerator < epsilon) 220 | return "0/0"; 221 | else 222 | return "?/0"; 223 | } 224 | return oneDecimal(static_cast(numerator) / denominator); 225 | } 226 | 227 | std::string ColumnPrinter::oneDecimal(const double d) { 228 | std::ostringstream out; 229 | unsigned long long l = static_cast(d * 10 + 0.5); 230 | out << l / 10 << '.' << l % 10; 231 | return out.str(); 232 | } 233 | 234 | std::string ColumnPrinter::withSIPrefix(unsigned long long l) { 235 | std::ostringstream out; 236 | if (l < 1000) 237 | out << l; 238 | else { 239 | const char* const units[] = {"k", "M", "G", "T"}; 240 | const size_t unitCount = sizeof(units) / sizeof(*units); 241 | double amount = static_cast(l) / 1000.0; 242 | size_t i = 0; 243 | // the stop condition is at 999.5 because that value will get 244 | // rounded to 1000.0. 245 | for (i = 0; i < unitCount && amount >= 999.95; ++i) 246 | amount /= 1000.0; 247 | out << oneDecimal(amount) << units[i]; 248 | } 249 | return out.str(); 250 | } 251 | 252 | std::string ColumnPrinter::bytesInUnit(const unsigned long long bytes) { 253 | std::ostringstream out; 254 | if (bytes < 1024) 255 | out << bytes << 'B'; 256 | else { 257 | const char* const units[] = {"kB", "MB", "GB", "TB"}; 258 | const size_t unitCount = sizeof(units) / sizeof(*units); 259 | double amount = static_cast(bytes) / 1024.0; 260 | size_t i = 0; 261 | // the stop condition is 1023.95 because that value will get 262 | // rounded to 1024.0. 263 | for (i = 0; i < unitCount && amount >= 1023.95; ++i) 264 | amount /= 1024.0; 265 | out << oneDecimal(amount) << units[i]; 266 | } 267 | return out.str(); 268 | } 269 | 270 | 271 | std::ostream& operator<<( 272 | std::ostream& out, 273 | const ColumnPrinter& printer 274 | ) { 275 | printer.print(out); 276 | return out; 277 | } 278 | 279 | void print(FILE* out, const ColumnPrinter& pr) { 280 | std::ostringstream str; 281 | str << pr; 282 | fputs(str.str().c_str(), out); 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /src/mathic/ColumnPrinter.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_COLUMN_PRINTER_GUARD 2 | #define MATHIC_COLUMN_PRINTER_GUARD 3 | 4 | #include "stdinc.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace mathic { 12 | class ColumnPrinter { 13 | public: 14 | ColumnPrinter(size_t columnCount = 0); 15 | 16 | void setPrefix(const std::string& prefix); 17 | std::ostream& addColumn( 18 | bool flushLeft = true, 19 | const std::string& prefix = " ", 20 | const std::string& suffix = "" 21 | ); 22 | size_t getColumnCount() const; 23 | 24 | std::ostream& operator[](size_t col); 25 | 26 | /// Inserts a newline after padding the current line with repeatThis 27 | /// chars until it fills the column width. 28 | void repeatToEndOfLine(const char repeatThis, size_t col); 29 | 30 | /// Works on all columns. 31 | void repeatToEndOfLine(const char repeatThis); 32 | 33 | void print(std::ostream& out) const; 34 | 35 | /// Returns "123,456,789" for parameter value 123456789. 36 | static std::string commafy(unsigned long long l); 37 | 38 | /// Returns "123.4G" for parameter value 123456789. So the SI prefix is a 39 | /// suffix of the returned string, yet it is still called an SI *prefix* 40 | /// because these are usually used as prefixes to units such as in Km. 41 | static std::string withSIPrefix(unsigned long long l); 42 | 43 | /** returns (3,100) as "3.0%". */ 44 | static std::string percentInteger( 45 | unsigned long long numerator, 46 | unsigned long long denominator 47 | ); 48 | static std::string percentDouble(double numerator, double denominator); 49 | 50 | /** returns (3,100) as " 3.0%". The string always has the same length for 51 | ratios equal to or less than 999.9%. */ 52 | static std::string percentIntegerFixed( 53 | unsigned long long numerator, 54 | unsigned long long denominator); 55 | 56 | /** returns 0.7565 as "75.7%". */ 57 | static std::string percentDouble(double ratio); 58 | 59 | /** Returns (7,4) as "1.8" */ 60 | static std::string ratioInteger( 61 | unsigned long long numerator, 62 | unsigned long long denominator 63 | ); 64 | static std::string ratioDouble(double numerator, double denominator); 65 | 66 | /** Returns d as a string printed to 1 decimal place, rounding up at 0.5 */ 67 | static std::string oneDecimal(double d); 68 | 69 | /** Prints as X bytes, X kilobytes, X megabytes etc. */ 70 | static std::string bytesInUnit(unsigned long long bytes); 71 | 72 | private: 73 | struct Col { 74 | std::string prefix; 75 | std::stringstream text; 76 | std::string suffix; 77 | bool flushLeft; 78 | std::vector > repeatToEndOfLine; 79 | }; 80 | std::vector> _cols; 81 | std::string _prefix; 82 | }; 83 | 84 | std::ostream& operator<<(std::ostream& out, const ColumnPrinter& printer); 85 | void print(FILE* out, const ColumnPrinter& pr); 86 | } 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /src/mathic/ComTree.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_COM_TREE_GUARD 2 | #define MATHIC_COM_TREE_GUARD 3 | 4 | #include "stdinc.h" 5 | #include 6 | 7 | namespace mathic { 8 | /** This class packs a complete binary tree in a vector. 9 | 10 | The idea is to have the root at index 1, and then the left child of node n 11 | will be at index 2n and the right child will be at index 2n + 1. The 12 | corresponding formulas when indexes start at 0 take more computation, so 13 | we need a 1-based array so we can't use std::vector. 14 | 15 | Also, when sizeof(Entry) is a power of 2 it is faster to keep track of 16 | i * sizeof(Entry) than directly keeping track of an index i. This doesn't 17 | work well when sizeof(Entry) is not a power of two. So we need both 18 | possibilities. That is why this class never exposes indexes. Instead 19 | you interact with Node objects that serve the role of an index, but the 20 | precise value it stores is encapsulated. This way you can't do something 21 | like _array[i * sizeof(Entry)] by accident. Client code also does not 22 | need to (indeed, can't) be aware of how indexes are calculated, stored and 23 | looked up. 24 | 25 | If FastIndex is false, then Nodes contain an index i. If FastIndex is 26 | true, then Nodes contain the byte offset i * sizeof(Entry). FastIndex must 27 | be false if sizeof(Entry) is not a power of two. 28 | */ 29 | template 30 | class ComTree { 31 | public: 32 | class Node; 33 | ComTree(size_t initialCapacity = 0); 34 | ComTree(const ComTree& tree, size_t minCapacity = 0); 35 | ComTree(ComTree&& tree); 36 | 37 | ~ComTree() { 38 | MATHIC_ASSERT(isValid()); 39 | delete[](_arrayKeepAlive); 40 | } 41 | 42 | Entry& operator[](Node n); 43 | const Entry& operator[](Node n) const; 44 | 45 | bool empty() const {return _lastLeaf == Node(0);} 46 | size_t size() const {return _lastLeaf.getNormalIndex();} 47 | size_t capacity() const {return _capacityEnd.getNormalIndex();} 48 | Node lastLeaf() const {return _lastLeaf;} 49 | 50 | void pushBack(const Entry& value); 51 | void pushBackWithCapacity(const Entry& value); 52 | void popBack(); 53 | 54 | bool hasFreeCapacity(size_t extraCapacity) const; 55 | void increaseCapacity(); 56 | void swap(ComTree& tree); 57 | 58 | class Node { 59 | public: 60 | Node(): _index(fi ? S : 1) {} // the root node is the default 61 | 62 | Node parent() const; 63 | Node left() const; 64 | Node right() const; 65 | Node sibling() const; 66 | Node leftSibling() const; 67 | Node next() const; 68 | Node next(size_t count) const; 69 | Node prev() const; 70 | Node& operator++() {*this = next(); return *this;} 71 | 72 | bool isRoot() const {return *this == Node();} 73 | 74 | // Returns a size_t instead of a bool so that the compiler does not 75 | // have to convert to bool (this silences a MSVC performance warning). 76 | size_t isLeft() const {return fi ? !(_index & S) : !(_index & 1);} 77 | 78 | // Returns a size_t instead of a bool so that the compiler does not 79 | // have to convert to bool (this silences a MSVC performance warning). 80 | size_t isRight() const {return fi ? _index & S : _index & 1;} 81 | 82 | bool operator<(Node node) const {return _index < node._index;} 83 | bool operator<=(Node node) const {return _index <= node._index;} 84 | bool operator>(Node node) const {return _index > node._index;} 85 | bool operator>=(Node node) const {return _index >= node._index;} 86 | bool operator==(Node node) const {return _index == node._index;} 87 | bool operator!=(Node node) const {return _index != node._index;} 88 | 89 | //private: 90 | friend class ComTree; 91 | static const bool fi = FastIndex; 92 | static const size_t S = sizeof(Entry); 93 | explicit Node(size_t i): _index(i) {} 94 | size_t getNormalIndex() const {return fi ? _index / S : _index;} 95 | size_t _index; 96 | }; 97 | 98 | void print(std::ostream& out) const; 99 | 100 | void clear(); 101 | 102 | size_t getMemoryUse() const; 103 | 104 | /// Asserts internal invariants if asserts are turned on. 105 | bool isValid() const; 106 | 107 | private: 108 | ComTree& operator=(const ComTree& tree) const; // not available 109 | 110 | Entry* _array; 111 | 112 | /// Macaulay 2 uses Mathic and Macaulay 2 also uses the Boehm garbage 113 | /// collector. Since _array points to a place before the array we 114 | /// are using, that array will be garbage collected if we do not 115 | /// keep around a second pointer that does point into the array. 116 | /// That is the purpose of _arrayKeepAlive. 117 | Entry* _arrayKeepAlive; 118 | 119 | Node _lastLeaf; 120 | Node _capacityEnd; 121 | }; 122 | 123 | template 124 | void ComTree::clear() { 125 | _lastLeaf = Node(0); 126 | } 127 | 128 | template 129 | size_t ComTree::getMemoryUse() const { 130 | return capacity() * sizeof(E); 131 | } 132 | 133 | template 134 | std::ostream& operator<<(std::ostream& out, const ComTree& tree) { 135 | tree.print(out); 136 | return out; 137 | } 138 | 139 | template 140 | ComTree::ComTree(size_t initialCapacity): 141 | _array(static_cast(0) - 1), 142 | _arrayKeepAlive(0), 143 | _lastLeaf(0), 144 | _capacityEnd(Node(0).next(initialCapacity)) 145 | { 146 | if (initialCapacity > 0) { 147 | _arrayKeepAlive = new E[initialCapacity]; 148 | _array = _arrayKeepAlive - 1; 149 | } 150 | MATHIC_ASSERT(isValid()); 151 | } 152 | 153 | template 154 | ComTree::ComTree(const ComTree& tree, size_t minCapacity): 155 | _array(static_cast(0) - 1), 156 | _arrayKeepAlive(0), 157 | _lastLeaf(tree._lastLeaf) 158 | { 159 | if (tree.size() > minCapacity) 160 | minCapacity = tree.size(); 161 | _capacityEnd = Node(0).next(minCapacity); 162 | if (minCapacity != 0) { 163 | _arrayKeepAlive = new E[minCapacity]; 164 | _array = _arrayKeepAlive - 1; 165 | for (Node i; i <= tree.lastLeaf(); ++i) 166 | (*this)[i] = tree[i]; 167 | } 168 | 169 | MATHIC_ASSERT(isValid()); 170 | } 171 | 172 | template 173 | ComTree::ComTree(ComTree&& tree): 174 | _array(tree._array), 175 | _arrayKeepAlive(tree._arrayKeepAlive), 176 | _lastLeaf(tree._lastLeaf), 177 | _capacityEnd(tree._capacityEnd) 178 | { 179 | tree._array = static_cast(0) - 1; 180 | tree._arrayKeepAlive = 0; 181 | _lastLeaf = Node(0); 182 | _capacityEnd = Node(0); 183 | } 184 | 185 | template 186 | inline E& ComTree::operator[](Node n) { 187 | MATHIC_ASSERT(_array == _arrayKeepAlive - 1); 188 | if (!FI) 189 | return _array[n._index]; 190 | char* base = reinterpret_cast(_array); 191 | E* element = reinterpret_cast(base + n._index); 192 | MATHIC_ASSERT(element == &(_array[n._index / sizeof(E)])); 193 | return *element; 194 | } 195 | 196 | template 197 | inline const E& ComTree::operator[](Node n) const { 198 | return const_cast*>(this)->operator[](n); 199 | } 200 | 201 | template 202 | void ComTree::pushBack(const E& value) { 203 | if (_lastLeaf == _capacityEnd) 204 | increaseCapacity(); 205 | _lastLeaf = _lastLeaf.next(); 206 | (*this)[lastLeaf()] = value; 207 | } 208 | 209 | template 210 | void ComTree::pushBackWithCapacity(const E& value) { 211 | MATHIC_ASSERT(_lastLeaf != _capacityEnd); 212 | _lastLeaf = _lastLeaf.next(); 213 | (*this)[lastLeaf()] = value; 214 | } 215 | 216 | template 217 | void ComTree::popBack() { 218 | MATHIC_ASSERT(_lastLeaf >= Node()); 219 | _lastLeaf = _lastLeaf.prev(); 220 | } 221 | 222 | template 223 | void ComTree::swap(ComTree& tree) { 224 | MATHIC_ASSERT(isValid()); 225 | MATHIC_ASSERT(tree.isValid()); 226 | 227 | std::swap(_array, tree._array); 228 | std::swap(_arrayKeepAlive, tree._arrayKeepAlive); 229 | std::swap(_lastLeaf, tree._lastLeaf); 230 | std::swap(_capacityEnd, tree._capacityEnd); 231 | 232 | MATHIC_ASSERT(isValid()); 233 | MATHIC_ASSERT(tree.isValid()); 234 | } 235 | 236 | template 237 | typename ComTree::Node ComTree::Node::parent() const { 238 | return fi ? Node((_index / (2 * S)) * S) : Node(_index / 2); 239 | } 240 | 241 | template 242 | typename ComTree::Node ComTree::Node::left() const { 243 | return Node(2 * _index); 244 | } 245 | 246 | template 247 | typename ComTree::Node ComTree::Node::right() const { 248 | return fi ? Node(2 * _index + S) : Node(2 * _index + 1); 249 | } 250 | 251 | template 252 | typename ComTree::Node ComTree::Node::sibling() const { 253 | return fi ? Node(_index ^ S) : Node(_index ^ 1); 254 | } 255 | 256 | template 257 | typename ComTree::Node ComTree::Node::leftSibling() const { 258 | return fi ? Node(_index & ~S) : Node(_index & ~1); 259 | } 260 | 261 | template 262 | typename ComTree::Node ComTree::Node::next() const { 263 | return fi ? Node(_index + S) : Node(_index + 1); 264 | } 265 | 266 | template 267 | typename ComTree::Node ComTree::Node::next(size_t count) const { 268 | return fi ? Node(_index + S * count) : Node(_index + count); 269 | } 270 | 271 | template 272 | typename ComTree::Node ComTree::Node::prev() const { 273 | return fi ? Node(_index - S) : Node(_index - 1); 274 | } 275 | 276 | template 277 | void ComTree::print(std::ostream& out) const { 278 | Node last = lastLeaf(); 279 | for (Node i; i <= last; i = i.next()) { 280 | if ((i._index & (i._index - 1)) == 0) // if i._index is a power of 2 281 | out << "\n " << i._index << ':'; 282 | out << ' ' << (*this)[i]; 283 | } 284 | out << "}\n"; 285 | } 286 | 287 | template 288 | bool ComTree::isValid() const { 289 | #ifndef MATHIC_DEBUG 290 | return true; 291 | #else 292 | MATHIC_ASSERT(_array == _arrayKeepAlive - 1); 293 | 294 | // sizeof(Entry) must be a power of two if FastIndex is true. 295 | MATHIC_ASSERT(!FI || (sizeof(E) & (sizeof(E) - 1)) == 0); 296 | if (capacity() == 0) { 297 | MATHIC_ASSERT(_array == static_cast(0) - 1); 298 | MATHIC_ASSERT(_capacityEnd == Node(0)); 299 | MATHIC_ASSERT(_lastLeaf == Node(0)); 300 | } else { 301 | MATHIC_ASSERT(_array != static_cast(0) - 1); 302 | MATHIC_ASSERT(_capacityEnd > Node(0)); 303 | MATHIC_ASSERT(_lastLeaf <= _capacityEnd); 304 | } 305 | return true; 306 | #endif 307 | } 308 | 309 | template 310 | bool ComTree::hasFreeCapacity(size_t extraCapacity) const { 311 | return Node(_capacityEnd._index - _lastLeaf._index) >= 312 | Node(0).next(extraCapacity); 313 | } 314 | 315 | template 316 | void ComTree::increaseCapacity() { 317 | MATHIC_ASSERT(isValid()); 318 | ComTree newTree(capacity() == 0 ? 16 : capacity() * 2); 319 | for (Node i; i <= lastLeaf(); i = i.next()) 320 | newTree.pushBack((*this)[i]); 321 | MATHIC_ASSERT(newTree.isValid()); 322 | std::swap(_array, newTree._array); 323 | std::swap(_arrayKeepAlive, newTree._arrayKeepAlive); 324 | std::swap(_capacityEnd, newTree._capacityEnd); 325 | MATHIC_ASSERT(isValid()); 326 | } 327 | } 328 | 329 | #endif 330 | -------------------------------------------------------------------------------- /src/mathic/Comparer.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_COMPARER_GUARD 2 | #define MATHIC_COMPARER_GUARD 3 | 4 | namespace mathic { 5 | template 6 | class Comparer { 7 | public: 8 | Comparer(const C& conf): _conf(conf) {} 9 | template 10 | bool operator()(const A& a, const B& b) const { 11 | return _conf.isLessThan(a.get(), b.get()); 12 | } 13 | private: 14 | const C& _conf; 15 | }; 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/mathic/DivFinder.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_DIV_FINDER_GUARD 2 | #define MATHIC_DIV_FINDER_GUARD 3 | 4 | /** An object that supports queries for divisors of a monomial. 5 | 6 | This is an object for documentation purposes. Use the concrete 7 | implementations of this interface to get an actual DivFinder-like 8 | object. 9 | 10 | DivFinder stores configurable Entry objects that represent a monomial 11 | together with any required additional information. 12 | 13 | The class is parameterized on a Configuration. The Configuration class 14 | must have the following members. 15 | 16 | * A type Monomial 17 | Represents a monomial. 18 | 19 | * A type Entry 20 | These are the things added to the finder. Entry represents a monomial 21 | along with any additional required information that client code needs 22 | to associate with monomials in the finder. 23 | 24 | * A type Exponent 25 | These are exponents of the monomials. Exponent must have a copy constructor, 26 | an operator= and an operator< for comparision with other exponents. 27 | 28 | * A function Exponent getExponent(Monomial m, size_t var) const 29 | Returns the exponent of the variable var in m. m can be a const reference. 30 | 31 | * A function bool divides(Entry a, Monomial b) const 32 | * A function bool divides(Monomial a, Entry b) const 33 | * A function bool divides(Entry a, Entry b) const 34 | Returns whether a divides b. a and b can be const references. If Entry 35 | and Monomial are the same type then only one function is needed. 36 | 37 | * A function size_t getVarCount() const 38 | Returns the number of variables. Variables are indexed from 0 to 39 | getVarCount() - 1. Must be a positive number. 40 | 41 | * static const bool UseDivMask 42 | Set to true to use div masks to speed up queries. This must be a 43 | static const data member. 44 | 45 | * size_t getUseAutomaticRebuild() const 46 | * double getRebuildRatio() const 47 | * size_t getRebuildMin() const 48 | If getUseAutomaticRebuild() returns true, the tree will call rebuild 49 | after a total of max(size() * getRebuildRatio(), getRebuildMin()) 50 | entry insertions and removals have occurred. A rebuild ratio of 0.5 51 | and a minimum of 500 has worked well for random vectors. 52 | 53 | * A method bool isLessThan(Entry a, Monomial b) const 54 | * A method bool isLessThan(Monomial a, Entry b) const 55 | * A method bool isLessThan(Entry a, Entry b) const 56 | isLessThan must define a total order < on entries/monomials. a and b can 57 | be const references. If Entry and Monomial are the same type then only 58 | one function is needed. 59 | 60 | It is possible to obtain non-const Entries from a DivFinder. It is allowed 61 | to change these, but the monomial they represent must not change. When the 62 | DivFinder calls some method X on the Configuration, the Configuration must 63 | not in return cause a method to be called on the DivFinder until the method 64 | X has returned. This is because the DivFinder may not be in a valid state 65 | at the time it is calling X. 66 | 67 | @todo: put these docs somewhere else. 68 | */ 69 | namespace { 70 | template 71 | class DivFinder; // no implementation 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/mathic/DivMask.cpp: -------------------------------------------------------------------------------- 1 | #include "DivMask.h" 2 | 3 | #ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO 4 | namespace mathic { 5 | namespace DivMaskStats { 6 | unsigned long maskComputes = 0; 7 | unsigned long maskChecks = 0; 8 | unsigned long maskHits = 0; 9 | unsigned long divChecks = 0; 10 | unsigned long divDivides = 0; 11 | unsigned long divHits = 0; 12 | } 13 | } 14 | #else 15 | // The purpose of dummy is to silence a MSVC linker warning 16 | // that says that this file is not adding anything to the build. 17 | namespace {void dummy(){}} 18 | #endif 19 | -------------------------------------------------------------------------------- /src/mathic/GeoFront.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_GEO_FRONT_GUARD 2 | #define MATHIC_GEO_FRONT_GUARD 3 | 4 | #include "stdinc.h" 5 | #include 6 | #include 7 | 8 | namespace mathic { 9 | /** 10 | To be used by Geobucket class. 11 | 12 | Configuration is the Configuration from the owning Geobucket. 13 | 14 | Bucket is the Bucket class from the owning Geobucket. Having Bucket be a 15 | parameter allows it to be used before it is declared so that this header 16 | need not include Geobucket's header, which would otherwise be a cyclic 17 | dependency. This also grants access to Geobucket::Bucket which is 18 | otherwise private. 19 | 20 | Why not make this an inner template class of Geobucket? Because inner 21 | template classes cannot be specialized without also specializing the 22 | outer class. 23 | */ 24 | 25 | template 26 | class Geobucket; 27 | 28 | template::Bucket, 30 | bool Order = Configuration::trackFront> 31 | class GeoFront; 32 | 33 | // ******************************************************************** 34 | // GeoFront maintaining no special order 35 | template 36 | class GeoFront { 37 | public: 38 | /** A reference is kept to entryCountRef so that it can be updated 39 | in the event of a deduplication. */ 40 | GeoFront(const C& conf, size_t& entryCountRef): 41 | _cachedMaxBucket(0), _entryCountRef(&entryCountRef), _conf(conf) { 42 | MATHIC_ASSERT(!C::trackFront); 43 | } 44 | 45 | void clear() { 46 | _cachedMaxBucket = 0; 47 | } 48 | 49 | void reserveCapacity(size_t newCapacity) {} 50 | void bucketsInvalidated(Bucket* oldBegin, Bucket* newBegin) { 51 | _cachedMaxBucket = 0; 52 | } 53 | bool empty() const {return *_entryCountRef == 0;} 54 | 55 | void insert(Bucket* bucket) {_cachedMaxBucket = 0;} 56 | void remove(Bucket* bucket) {_cachedMaxBucket = 0;} 57 | void keyIncreased(Bucket* bucket) {_cachedMaxBucket = 0;} 58 | void keyDecreased(Bucket* bucket) {_cachedMaxBucket = 0;} 59 | void swapKeys(Bucket* a, Bucket* b) {} 60 | bool larger(const Bucket* a, const Bucket* b) const { 61 | MATHIC_ASSERT(false); 62 | return false; 63 | } 64 | const Bucket* getMax(Bucket* bucketBegin, Bucket* bucketEnd) const; 65 | 66 | #ifdef MATHIC_DEBUG 67 | bool debugIsValid(Bucket* bucketBegin, Bucket* bucketEnd) const; 68 | #endif 69 | 70 | size_t getMemoryUse() const; 71 | 72 | private: 73 | const Bucket* computeMax(Bucket* bucketBegin, Bucket* bucketEnd) const; 74 | 75 | mutable const Bucket* _cachedMaxBucket; 76 | size_t* _entryCountRef; 77 | const C& _conf; 78 | }; 79 | 80 | template 81 | size_t GeoFront::getMemoryUse() const { 82 | return 0; 83 | } 84 | 85 | template 86 | const B* GeoFront::getMax(B* bucketBegin, B* bucketEnd) const { 87 | // the point is that the compiler is more likely to compile this 88 | // pre-calculation so that computeMax won't get called in cases 89 | // where the maximum has already been computed. 90 | if (_cachedMaxBucket != 0) 91 | return _cachedMaxBucket; 92 | return computeMax(bucketBegin, bucketEnd); 93 | } 94 | 95 | template 96 | const B* GeoFront::computeMax 97 | (B* bucketBegin, B* bucketEnd) const { 98 | MATHIC_ASSERT(_cachedMaxBucket == 0); 99 | const B* maxBucket = bucketBegin; 100 | while (maxBucket->empty()) { 101 | ++maxBucket; 102 | MATHIC_ASSERT(maxBucket != bucketEnd); 103 | } 104 | for (const B* it = maxBucket + 1; it != bucketEnd; ++it) { 105 | if (it->empty()) 106 | continue; 107 | typename C::CompareResult cmp = 108 | _conf.compare(it->back(), maxBucket->back()); 109 | if (_conf.cmpLessThan(cmp)) 110 | continue; 111 | if (C::supportDeduplication && _conf.cmpEqual(cmp)) { 112 | B* mb = const_cast(maxBucket); 113 | mb->setEntry(mb->end() - 1, 114 | _conf.deduplicate(mb->back(), it->back())); 115 | const_cast(it)->pop_back(); 116 | --*_entryCountRef; 117 | continue; 118 | } 119 | maxBucket = it; 120 | } 121 | MATHIC_ASSERT(maxBucket != bucketEnd); 122 | return _cachedMaxBucket = maxBucket; 123 | } 124 | 125 | #ifdef MATHIC_DEBUG 126 | template 127 | bool GeoFront::debugIsValid(B* bucketBegin, B* bucketEnd) const { 128 | if (_cachedMaxBucket == 0) 129 | return true; 130 | MATHIC_ASSERT(!_cachedMaxBucket->empty()); 131 | for (B* bucket = bucketBegin; bucket != bucketEnd; ++bucket) { 132 | if (!bucket->empty()) { 133 | MATHIC_ASSERT(!_conf.cmpLessThan 134 | (_conf.compare(_cachedMaxBucket->back(), bucket->back()))); 135 | } 136 | } 137 | return true; 138 | } 139 | #endif 140 | 141 | // ******************************************************************** 142 | // GeoFront maintaining an ordered list 143 | template 144 | class GeoFront { 145 | public: 146 | GeoFront(const C& conf, size_t& entryCountRef); 147 | ~GeoFront() {delete[] _bucketBegin;} 148 | 149 | Bucket** begin() {return _bucketBegin;} 150 | Bucket*const* begin() const {return _bucketBegin;} 151 | Bucket** end() {return _bucketEnd;} 152 | Bucket*const* end() const {return _bucketEnd;} 153 | 154 | /** Can contain this many */ 155 | void reserveCapacity(size_t newCapacity); 156 | void bucketsInvalidated(Bucket* oldBegin, Bucket* newBegin); 157 | bool empty() const {return _bucketBegin == _bucketEnd;} 158 | 159 | void clear(); 160 | void insert(Bucket* bucket); 161 | void remove(Bucket* bucket); 162 | void keyIncreased(Bucket* bucket); 163 | void keyDecreased(Bucket* bucket); 164 | void swapKeys(Bucket* a, Bucket* b); 165 | bool larger(const Bucket* a, const Bucket* b) const; 166 | const Bucket* getMax(Bucket* bucketBegin, Bucket* bucketEnd) const; 167 | 168 | #ifdef MATHIC_DEBUG 169 | bool debugIsValid(Bucket* bucketBegin, Bucket* bucketEnd) const; 170 | #endif 171 | 172 | size_t getMemoryUse() const; 173 | 174 | private: 175 | size_t size() const {return _bucketEnd - _bucketBegin;} 176 | size_t capacity() const {return _bucketCapacityEnd - _bucketBegin;} 177 | 178 | Bucket** _bucketBegin; 179 | Bucket** _bucketEnd; 180 | Bucket** _bucketCapacityEnd; 181 | size_t* _entryCountRef; 182 | const C& _conf; 183 | }; 184 | 185 | template 186 | void GeoFront::clear() { 187 | _bucketEnd = _bucketBegin; 188 | } 189 | 190 | template 191 | size_t GeoFront::getMemoryUse() const { 192 | return capacity() * sizeof(*_bucketBegin); 193 | } 194 | 195 | template 196 | GeoFront::GeoFront(const C& conf, size_t& entryCountRef): 197 | _bucketBegin(0), 198 | _bucketEnd(0), 199 | _bucketCapacityEnd(0), 200 | _entryCountRef(&entryCountRef), 201 | _conf(conf) { 202 | MATHIC_ASSERT(C::trackFront); 203 | } 204 | 205 | template 206 | void GeoFront::reserveCapacity(size_t newCapacity) { 207 | MATHIC_ASSERT(newCapacity >= size()); 208 | if (newCapacity == 0) 209 | newCapacity = 1; 210 | size_t const oldSize = size(); 211 | B** const oldBegin = _bucketBegin; 212 | B** const oldEnd = _bucketEnd; 213 | _bucketBegin = new B*[newCapacity]; 214 | _bucketEnd = _bucketBegin + oldSize; 215 | _bucketCapacityEnd = _bucketBegin + newCapacity; 216 | std::copy(oldBegin, oldEnd, _bucketBegin); 217 | 218 | // the tokens point into the old space, so map them to an index 219 | // and then back to a pointer into the newly allocated memory. 220 | for (B** bucket = _bucketBegin; bucket != _bucketEnd; ++bucket) { 221 | B** token = (*bucket)->getFrontToken(); 222 | token = (token - oldBegin) + _bucketBegin; 223 | (*bucket)->setFrontToken(token); 224 | } 225 | delete[] oldBegin; 226 | } 227 | 228 | template 229 | void GeoFront::bucketsInvalidated 230 | (B* oldBegin, B* newBegin) { 231 | // _buckets points into an array of buckets that has been reallocated, 232 | // so we need to go to an index and back to update the pointers 233 | // to point into the new memory area. 234 | if (empty()) 235 | return; 236 | for (B** bucket = begin(); bucket != end(); ++bucket) 237 | *bucket = (*bucket - oldBegin) + newBegin; 238 | } 239 | 240 | template 241 | void GeoFront::insert(B* bucket) { 242 | if (!C::trackFront) 243 | return; 244 | MATHIC_ASSERT(bucket != 0); 245 | MATHIC_ASSERT(bucket->_frontPos == 0); 246 | MATHIC_ASSERT(!bucket->empty()); 247 | if (_bucketEnd == _bucketCapacityEnd) 248 | reserveCapacity(size() + 1); 249 | *_bucketEnd = bucket; 250 | ++_bucketEnd; 251 | bucket->_frontPos = end() - 1; 252 | keyIncreased(bucket); 253 | } 254 | 255 | template 256 | void GeoFront::keyIncreased(B* bucket) { 257 | B** pos = bucket->_frontPos; 258 | B** begin = this->begin(); 259 | for (; pos != begin; --pos) { // move bucket to lower index 260 | B& shouldBeGreater = **(pos - 1); 261 | typename C::CompareResult cmp = 262 | _conf.compare(shouldBeGreater.back(), bucket->back()); 263 | if (!_conf.cmpLessThan(cmp)) 264 | break; 265 | // todo: if equal 266 | *pos = *(pos - 1); 267 | shouldBeGreater._frontPos = pos; 268 | } 269 | // We don't have to adjust bucket's position if it never moved, but 270 | // detecting that without extra branches makes the code too complex 271 | // for it to be worth it. 272 | *pos = bucket; 273 | bucket->_frontPos = pos; 274 | } 275 | 276 | template 277 | void GeoFront::keyDecreased(B* bucket) { 278 | if (bucket->empty()) { 279 | remove(bucket); 280 | return; 281 | } 282 | B** pos = bucket->_frontPos; 283 | B** end = this->end(); 284 | for (; pos + 1 != end; ++pos) { // move bucket to higher index 285 | B& otherBucket = **(pos + 1); 286 | typename C::CompareResult cmp = 287 | _conf.compare(bucket->back(), otherBucket.back()); 288 | if (!_conf.cmpLessThan(cmp)) { 289 | if (!C::supportDeduplication || !_conf.cmpEqual(cmp)) 290 | break; // greater than, found correct position 291 | otherBucket.setEntry(otherBucket.end() - 1, 292 | _conf.deduplicate(bucket->back(), otherBucket.back())); 293 | bucket->pop_back(); 294 | --*_entryCountRef; 295 | if (bucket->empty()) { 296 | bucket->_frontPos = pos; 297 | remove(bucket); 298 | return; 299 | } 300 | } 301 | *pos = *(pos + 1); 302 | otherBucket._frontPos = pos; 303 | } 304 | // We don't have to adjust bucket's position if it never moved, but 305 | // detecting that without extra branches makes the code too complex 306 | // for it to be worth it. 307 | *pos = bucket; 308 | bucket->_frontPos = pos; 309 | } 310 | 311 | template 312 | void GeoFront::remove(B* bucket) { 313 | MATHIC_ASSERT(bucket->_frontPos != 0); 314 | MATHIC_ASSERT(bucket->empty()); 315 | B** end = this->end(); // can't dereference end 316 | for (B** i = bucket->_frontPos + 1; i != end; ++i) { 317 | *(i - 1) = *i; 318 | (*i)->_frontPos = i - 1; 319 | } 320 | --_bucketEnd; 321 | bucket->_frontPos = 0; 322 | } 323 | 324 | template 325 | void GeoFront::swapKeys(B* a, B* b) { 326 | MATHIC_ASSERT(a != 0); 327 | MATHIC_ASSERT(b != 0); 328 | std::swap(a->_frontPos, b->_frontPos); 329 | if (a->_frontPos != 0) 330 | *a->_frontPos = a; 331 | if (b->_frontPos != 0) 332 | *b->_frontPos = b; 333 | } 334 | 335 | template 336 | bool GeoFront::larger(const B* a, const B* b) const { 337 | MATHIC_ASSERT(a != 0); 338 | MATHIC_ASSERT(b != 0); 339 | return a->_frontPos < b->_frontPos; 340 | } 341 | 342 | template 343 | const B* GeoFront::getMax(B* bucketBegin, B* bucketEnd) const { 344 | MATHIC_ASSERT(!empty()); 345 | return *begin(); 346 | } 347 | 348 | #ifdef MATHIC_DEBUG 349 | template 350 | bool GeoFront::debugIsValid(B* bucketBegin, B* bucketEnd) const { 351 | std::vector nonEmpty; 352 | size_t size = bucketEnd - bucketBegin; 353 | for (size_t b = 0; b < size; ++b) { 354 | if (bucketBegin[b].empty()) { 355 | MATHIC_ASSERT(bucketBegin[b]._frontPos == 0); 356 | } else { 357 | MATHIC_ASSERT(bucketBegin[b]._frontPos != 0); 358 | MATHIC_ASSERT(*(bucketBegin[b]._frontPos) == &(bucketBegin[b])); 359 | nonEmpty.push_back(&(bucketBegin[b])); 360 | } 361 | } 362 | std::vector frontCopy(_bucketBegin, _bucketEnd); 363 | std::sort(nonEmpty.begin(), nonEmpty.end()); 364 | std::sort(frontCopy.begin(), frontCopy.end()); 365 | MATHIC_ASSERT(std::equal(frontCopy.begin(), frontCopy.end(), nonEmpty.begin())); 366 | if (!empty()) { 367 | for (B** it = _bucketBegin + 1; it != _bucketEnd; ++it) 368 | MATHIC_ASSERT(!_conf.cmpLessThan 369 | (_conf.compare((*(it - 1))->back(), (*it)->back()))); 370 | } 371 | return true; 372 | } 373 | #endif 374 | } 375 | 376 | #endif 377 | -------------------------------------------------------------------------------- /src/mathic/HashTable.h: -------------------------------------------------------------------------------- 1 | // MathicGB copyright 2012 all rights reserved. MathicGB comes with ABSOLUTELY 2 | // NO WARRANTY and is licensed as GPL v2.0 or later - see LICENSE.txt. 3 | 4 | 5 | // issues: 6 | // 1. memory management of nodes 7 | // 2. statistics gathering 8 | // 3. resizing 9 | // 4. put ASSERT's in, to check for all manner of contracts 10 | 11 | // Notes to self: 12 | // see http://attractivechaos.wordpress.com/2008/08/28/comparison-of-hash-table-libraries/ 13 | 14 | #ifndef MATHIC_HASHTABLE_GUARD 15 | #define MATHIC_HASHTABLE_GUARD 16 | 17 | #include "stdinc.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace mathic { 25 | 26 | template 27 | class HashTable; 28 | 29 | class BasicHashTableConfiguration { 30 | typedef int Key; 31 | typedef int Value; 32 | 33 | size_t hash(Key k); 34 | bool keysEqual(Key k1, Key k2); 35 | }; 36 | 37 | template 38 | class HashTable; 39 | 40 | template 41 | class HashTable { 42 | public: 43 | typedef C Configuration; 44 | typedef typename C::Key Key; 45 | typedef typename C::Value Value; 46 | 47 | // Allowed actions for a Node* returned by lookup or insert: 48 | // 1. Key is const, while the Node* is in the hash table. 49 | // 2. Value can be modified by the callee at any time 50 | // 3. The 'next' field should not be referenced. 51 | // As for allocating and deallocating Node*: 52 | // Do not allocate your own: only use Node* 's returned by the package 53 | // There is no need to deallocate a Node*: when a 'reset() is done, all 54 | // Node* 's which have been allocated are deallocated at one time. 55 | // When this happens, the Key and Value are not deallocated? 56 | // If 'remove' returns a Node*, then it is safe to change the key and/or value, e.g. 57 | // to free the space pointed to by 'key' (if that is a pointer value, for instance). 58 | 59 | class Handle { 60 | public: 61 | friend class HashTable; 62 | 63 | Handle(Key k, Value v): 64 | next(0), 65 | entry(k,v) 66 | {} 67 | 68 | const Key& key() const {return entry.first;} 69 | const Value& value() const {return entry.second;} 70 | Value& value() {return entry.second;} 71 | void setKeyButOnlyDoSoIfThisHandleIsNotInHashTable(Key &new_k) {entry.first=new_k;} 72 | private: 73 | Handle *next; 74 | std::pair entry; 75 | }; 76 | 77 | // Create a hash table 78 | HashTable(const Configuration &conf, unsigned int nbits = 10); 79 | 80 | ~HashTable() {} 81 | 82 | // Returns the stored configuration. 83 | Configuration& configuration() {return mConf;} 84 | 85 | // Returns the stored configuration. 86 | Configuration const& configuration() const {return mConf;} 87 | 88 | // insert the key 'k' into the hash table. If the key is already there, 89 | // and return std::pair(false, ...) 90 | // else return std::pair(true, node in the hash table). 91 | std::pair insert(Key const& k, Value const& v); 92 | 93 | // If 'k' is present in the hash table, then its 'Node*' is returned. 94 | // If not, then NULL is returned. 95 | Handle* lookup(const Key &k); 96 | 97 | // remove 'p' from the hash table. 'p' itself is also removed. 98 | // what about the entries in 'p'? Are the destructors called? 99 | void remove(Handle* & p); 100 | 101 | void reset(); // Major assumption: all nodes have been removed from the table already 102 | 103 | void hardReset(); // Slow, avoid if possible. 104 | 105 | // Returns how many bytes of memory this data structure consumes 106 | // not including sizeof(*this). 107 | size_t memoryUse() const; 108 | 109 | // Returns a string that describes how this data structure was 110 | // configured. 111 | std::string name() const; 112 | 113 | private: 114 | Handle* makeNode(const Key &k, const Value &v); 115 | 116 | void grow(unsigned int nbits); 117 | 118 | // Used for consistency checking. Returns the number of nodes in the table. 119 | // Should match mNodeCount. 120 | size_t computeNodeCount() const; 121 | 122 | // Used for consistency checking. Returns the number of nonempty bins in the hash table. 123 | // Should match mBinCount. 124 | size_t computeBinCount() const; 125 | 126 | size_t mHashMask; // this is the number, in binary: 00001111...1, where 127 | // the number of 1's is mLogTableSize 128 | size_t mTableSize; 129 | size_t mLogTableSize; // number of bits in the table: mTableSize should be 2^mLogTableSize 130 | 131 | size_t mNodeCount; // current number of nodes in the hash table 132 | size_t mBinCount; // number of nonzero bins 133 | 134 | size_t mMaxCountBeforeRebuild; 135 | 136 | // tweakable parameters 137 | double mRebuildThreshold; 138 | bool mAlwaysInsertAtEnd; 139 | 140 | memt::BufferPool mNodePool; 141 | std::vector mHashTable; 142 | Configuration mConf; 143 | }; 144 | 145 | template 146 | HashTable::HashTable(const Configuration &conf, unsigned int nbits): 147 | mLogTableSize(nbits), 148 | mTableSize(static_cast(1) << nbits), 149 | mHashMask((static_cast(1) << nbits) - 1), 150 | mNodeCount(0), 151 | mBinCount(0), 152 | mRebuildThreshold(0.1), 153 | mAlwaysInsertAtEnd(true), 154 | mNodePool(sizeof(Handle)), 155 | mConf(conf) 156 | { 157 | mHashTable.resize(mTableSize); 158 | mMaxCountBeforeRebuild = static_cast(mRebuildThreshold * mTableSize); 159 | } 160 | 161 | template 162 | void HashTable::reset() { 163 | mNodePool.freeAllBuffers(); 164 | } 165 | 166 | template 167 | typename HashTable::Handle *HashTable::makeNode(const Key &k, const Value &v) 168 | { 169 | mNodeCount++; 170 | void *buf = mNodePool.alloc(); 171 | Handle* result = new (buf) Handle(k,v); 172 | return result; 173 | } 174 | 175 | template 176 | std::pair::Handle *> HashTable::insert(const Key &k, const Value &v) 177 | { 178 | size_t hashval = mConf.hash(k) & mHashMask; 179 | 180 | MATHIC_ASSERT(hashval < mHashTable.size()); 181 | Handle *tmpNode = mHashTable[hashval]; 182 | Handle *result = 0; 183 | if (tmpNode == 0) 184 | { 185 | result = makeNode(k,v); 186 | mHashTable[hashval] = result; 187 | } 188 | else 189 | { 190 | while (true) 191 | { 192 | if (mConf.keysEqual(tmpNode->key(), k)) 193 | { 194 | result = tmpNode; 195 | return std::pair(false,result); 196 | } 197 | if (tmpNode->next == 0) 198 | { 199 | // time to insert the monomial 200 | result = makeNode(k, v); 201 | if (mAlwaysInsertAtEnd) 202 | { 203 | tmpNode->next = result; 204 | } 205 | else 206 | { 207 | result->next = mHashTable[hashval]; 208 | mHashTable[hashval] = result; 209 | } 210 | break; 211 | } 212 | tmpNode = tmpNode->next; 213 | } 214 | } 215 | 216 | if (mNodeCount > mMaxCountBeforeRebuild) 217 | grow(static_cast(mLogTableSize + 2)); // increase by a factor of 4?? 218 | 219 | MATHIC_ASSERT(computeNodeCount() == mNodeCount); 220 | return std::pair(true,result); 221 | } 222 | 223 | template 224 | typename HashTable::Handle * HashTable::lookup(const Key &k) 225 | { 226 | size_t hashval = mConf.hash(k) & mHashMask; 227 | 228 | MATHIC_ASSERT(hashval < mHashTable.size()); 229 | for (Handle *p = mHashTable[hashval]; p != 0; p = p->next) 230 | { 231 | if (mConf.keysEqual(p->key(), k)) 232 | return p; 233 | } 234 | return NULL; 235 | } 236 | 237 | template 238 | void HashTable::remove(Handle *& p) 239 | { 240 | mNodeCount--; 241 | size_t const hashval = mConf.hashvalue(p->key) & mHashMask; 242 | Handle head; 243 | Handle* tmpNode = mHashTable[hashval]; 244 | head.next = tmpNode; 245 | for (Handle* q = &head; q->next != 0; q = q->next) 246 | { 247 | if (q->next == p) 248 | { 249 | q->next = p->next; 250 | mHashTable[hashval] = head.next; 251 | if (head.next == 0) mBinCount--; 252 | //TODO: call destructor for pair, then call 'free' with the mNodePool 253 | return; 254 | } 255 | } 256 | // If we get here, then the node is not at its supposed hash value. 257 | // That probably means either that the node has been deleted twice 258 | // or that the value in the node changed so that its hash value 259 | // changed. That is not allowed. 260 | MATHIC_ASSERT(false); 261 | } 262 | 263 | template 264 | void HashTable::grow(unsigned int new_nbits) 265 | { 266 | MATHIC_ASSERT(computeNodeCount() == mNodeCount); 267 | size_t const old_table_size = mTableSize; 268 | mTableSize = static_cast(1) << new_nbits; 269 | mLogTableSize = new_nbits; 270 | mHashMask = mTableSize-1; 271 | std::vector old_table(mTableSize); 272 | std::swap(old_table, mHashTable); 273 | 274 | mBinCount = 0; 275 | for (size_t i = 0; i < old_table_size; ++i) 276 | { 277 | Handle *p = old_table[i]; 278 | while (p != 0) 279 | { 280 | Handle *q = p; 281 | p = p->next; 282 | q->next = 0; 283 | // Reinsert node. We know that it is unique 284 | size_t hashval = mConf.hash(q->key()) & mHashMask; 285 | Handle *r = mHashTable[hashval]; 286 | if (r == 0) mBinCount++; 287 | if (r == 0 || !mAlwaysInsertAtEnd) 288 | { 289 | q->next = r; 290 | mHashTable[hashval] = q; 291 | } 292 | else 293 | { 294 | // put it at the end 295 | for ( ; r->next != 0; r = r->next) { } 296 | r->next = q; 297 | } 298 | } 299 | } 300 | 301 | mMaxCountBeforeRebuild = 302 | static_cast(std::floor(mTableSize * mRebuildThreshold)); 303 | 304 | MATHIC_ASSERT(computeNodeCount() == mNodeCount); 305 | } 306 | 307 | template 308 | size_t HashTable::memoryUse() const 309 | { 310 | size_t result = mHashTable.capacity() * sizeof(Handle *); 311 | result += mNodePool.getMemoryUse(); 312 | return result; 313 | } 314 | 315 | template 316 | size_t HashTable::computeNodeCount() const 317 | { 318 | size_t result = 0; 319 | for (size_t i=0; inext) result++; 322 | } 323 | return result; 324 | } 325 | 326 | template 327 | size_t HashTable::computeBinCount() const 328 | { 329 | size_t result = 0; 330 | for (size_t i=0; i 338 | std::string HashTable::name() const 339 | { 340 | return std::string("HashTable"); 341 | } 342 | 343 | } // namespace mathic 344 | 345 | #endif 346 | 347 | // Local Variables: 348 | // indent-tabs-mode: nil 349 | // mode: c++ 350 | // compile-command: "make -C $MATHIC/mathic " 351 | // End: 352 | 353 | -------------------------------------------------------------------------------- /src/mathic/Heap.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_HEAP_GUARD 2 | #define MATHIC_HEAP_GUARD 3 | 4 | #include "stdinc.h" 5 | #include "ComTree.h" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace mathic { 11 | /** A heap priority queue. 12 | 13 | Configuration serves the same role as for Geobucket. It must have these 14 | fields that work as for Geobucket. 15 | 16 | * A type Entry 17 | * A type CompareResult 18 | * A const or static method: CompareResult compare(Entry, Entry) 19 | * A const or static method: bool cmpLessThan(CompareResult) 20 | * A static const bool supportDeduplication 21 | * A static or const method: bool cmpEqual(CompareResult) 22 | 23 | It also has these additional fields: 24 | 25 | * A static const bool fastIndex 26 | If this field is true, then a faster way of calculating indexes is used. 27 | This requires sizeof(Entry) to be a power of two! This can be achieved 28 | by adding padding to Entry, but this class does not do that for you. 29 | */ 30 | template 31 | class Heap { 32 | public: 33 | typedef C Configuration; 34 | typedef typename Configuration::Entry Entry; 35 | 36 | Heap(const Configuration& configuration): _conf(configuration) {} 37 | Heap(const Configuration&& configuration): 38 | _conf(std::move(configuration)) {} 39 | Heap(Heap&& heap): _tree(std::move(_tree)), _conf(std::move(heap._conf)) {} 40 | 41 | Configuration& getConfiguration() {return _conf;} 42 | const Configuration& getConfiguration() const {return _conf;} 43 | 44 | template 45 | void forAll(T& t) const { 46 | Node stop = _tree.lastLeaf().next(); 47 | for (Node it = Node(); it != stop; ++it) 48 | if (!t.proceed(_tree[it])) 49 | return; 50 | } 51 | 52 | std::string getName() const; 53 | void push(Entry entry); 54 | 55 | template 56 | void push(It begin, It end); 57 | 58 | void clear(); 59 | Entry pop(); 60 | Entry top() const {return _tree[Node()];} 61 | bool empty() const {return _tree.empty();} 62 | size_t size() const {return _tree.size();} 63 | 64 | void print(std::ostream& out) const; 65 | 66 | void decreaseTop(Entry newEntry); 67 | 68 | size_t getMemoryUse() const; 69 | 70 | private: 71 | typedef ComTree Tree; 72 | typedef typename Tree::Node Node; 73 | 74 | Node moveHoleDown(Node hole); 75 | void moveValueUp(Node pos, Entry value); 76 | 77 | /// Asserts internal invariants if asserts are turned on. 78 | bool isValid() const; 79 | 80 | Tree _tree; 81 | Configuration _conf; 82 | }; 83 | 84 | template 85 | size_t Heap::getMemoryUse() const { 86 | return _tree.getMemoryUse(); 87 | } 88 | 89 | template 90 | std::string Heap::getName() const { 91 | return std::string("heap(") + 92 | (C::fastIndex ? "fi" : "si") + 93 | (C::supportDeduplication ? " dedup" : "") + 94 | ')'; 95 | } 96 | 97 | template 98 | void Heap::push(Entry entry) { 99 | _tree.pushBack(entry); 100 | moveValueUp(_tree.lastLeaf(), entry); 101 | MATHIC_SLOW_ASSERT(isValid()); 102 | } 103 | 104 | template 105 | template 106 | void Heap::push(It begin, It end) { 107 | for (; begin != end; ++begin) 108 | push(*begin); 109 | } 110 | 111 | template 112 | void Heap::decreaseTop(Entry newEntry) { 113 | moveValueUp(moveHoleDown(Node()), newEntry); 114 | MATHIC_SLOW_ASSERT(isValid()); 115 | } 116 | 117 | template 118 | void Heap::clear() { 119 | MATHIC_ASSERT(isValid()); 120 | _tree.clear(); 121 | MATHIC_ASSERT(isValid()); 122 | } 123 | 124 | template 125 | typename Heap::Entry Heap::pop() { 126 | Entry top = _tree[Node()]; 127 | Entry movedValue = _tree[_tree.lastLeaf()]; 128 | _tree.popBack(); 129 | if (!_tree.empty()) 130 | moveValueUp(moveHoleDown(Node()), movedValue); 131 | return top; 132 | MATHIC_SLOW_ASSERT(isValid()); 133 | } 134 | 135 | template 136 | void Heap::print(std::ostream& out) const { 137 | out << getName() << ": {" << _tree << "}\n"; 138 | } 139 | 140 | template 141 | typename Heap::Node Heap::moveHoleDown(Node hole) { 142 | const Node firstWithout2Children = _tree.lastLeaf().next().parent(); 143 | while (hole < firstWithout2Children) { 144 | // can assume hole has two children here 145 | Node child = hole.left(); 146 | Node sibling = child.next(); 147 | if (_conf.cmpLessThan(_conf.compare(_tree[child], _tree[sibling]))) 148 | child = sibling; 149 | _tree[hole] = _tree[child]; 150 | hole = child; 151 | } 152 | // if we are at a node that has a single left child 153 | if (hole == firstWithout2Children && _tree.lastLeaf().isLeft()) { 154 | Node child = hole.left(); 155 | _tree[hole] = _tree[child]; 156 | hole = child; 157 | } 158 | return hole; 159 | } 160 | 161 | template 162 | void Heap::moveValueUp(Node pos, Entry value) { 163 | const Node origPos = pos; 164 | again: 165 | while (!pos.isRoot()) { 166 | const Node up = pos.parent(); 167 | typename C::CompareResult cmp = _conf.compare(_tree[up], value); 168 | if (_conf.cmpLessThan(cmp)) { 169 | _tree[pos] = _tree[up]; 170 | pos = up; 171 | } else if (C::supportDeduplication && _conf.cmpEqual(cmp)) { 172 | _tree[up] = _conf.deduplicate(_tree[up], value); 173 | if (pos != origPos) { 174 | // move elements back 175 | Entry tmp = _tree[origPos]; 176 | for (Node p = origPos.parent(); p != pos; p = p.parent()) 177 | std::swap(tmp, _tree[p]); 178 | } 179 | pos = origPos; 180 | value = _tree[_tree.lastLeaf()]; 181 | _tree.popBack(); 182 | if (origPos == _tree.lastLeaf().next()) { 183 | MATHIC_SLOW_ASSERT(isValid()); 184 | return; 185 | } 186 | goto again; 187 | } else 188 | break; 189 | } 190 | _tree[pos] = value; 191 | MATHIC_SLOW_ASSERT(isValid()); 192 | } 193 | 194 | template 195 | bool Heap::isValid() const { 196 | #ifndef MATHIC_DEBUG 197 | return true; 198 | #else 199 | MATHIC_ASSERT(_tree.isValid()); 200 | for (Node i = Node().next(); i <= _tree.lastLeaf(); ++i) { 201 | MATHIC_ASSERT(!_conf.cmpLessThan(_conf.compare(_tree[i.parent()], _tree[i]))); 202 | } 203 | return true; 204 | #endif 205 | } 206 | } 207 | 208 | #endif 209 | -------------------------------------------------------------------------------- /src/mathic/HelpAction.cpp: -------------------------------------------------------------------------------- 1 | #include "HelpAction.h" 2 | 3 | #include "CliParameter.h" 4 | #include "error.h" 5 | #include "display.h" 6 | #include "ColumnPrinter.h" 7 | #include "CliParser.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace mathic { 13 | HelpAction::HelpAction() {} 14 | 15 | const char* HelpAction::name() const { 16 | return staticName(); 17 | } 18 | 19 | const char* HelpAction::description() const { 20 | return 21 | "Giving the parameter 'help' displays a list of the available actions.\n" 22 | "Giving the parameters 'help action' displays a detailed description of " 23 | "that action.\n"; 24 | } 25 | 26 | const char* HelpAction::shortDescription() const { 27 | return "Return information about the command line interface."; 28 | } 29 | 30 | void HelpAction::directOptions( 31 | std::vector tokens, 32 | CliParser& parser 33 | ) { 34 | _parser = &parser; 35 | if (tokens.size() == 1) 36 | _topic = tokens.front(); 37 | else if (tokens.size() > 1) 38 | reportError("Did not expect second option \"" + tokens[1] + "\"."); 39 | } 40 | 41 | void HelpAction::pushBackParameters(std::vector& parameters) { 42 | } 43 | 44 | namespace { 45 | // Helper function for displayActionHelp(). 46 | bool paramCmp(CliParameter* a, CliParameter* b) { 47 | MATHIC_ASSERT(a != 0); 48 | MATHIC_ASSERT(b != 0); 49 | return std::string(a->name()) < b->name(); 50 | } 51 | } 52 | 53 | void HelpAction::displayActionHelp(Action& action) { 54 | std::ostringstream out; 55 | out << "Displaying information on action: " << action.name() << "\n\n"; 56 | out << action.description() << "\n"; 57 | 58 | std::vector parameters; 59 | action.pushBackParameters(parameters); 60 | sort(parameters.begin(), parameters.end(), paramCmp); 61 | 62 | display(out.str()); 63 | 64 | if (!parameters.empty()) { 65 | fprintf(stderr, "\nThe parameters accepted by %s are as follows.\n", 66 | action.name()); 67 | 68 | typedef std::vector::const_iterator cit; 69 | for (cit it = parameters.begin(); it != parameters.end(); ++it) { 70 | std::string defaultValue = (*it)->valueAsString(); 71 | fprintf(stderr, "\n -%s %s (default is %s)\n", 72 | (*it)->name().c_str(), 73 | (*it)->argumentType().c_str(), 74 | (*it)->valueAsString().c_str()); 75 | display((*it)->description(), " "); 76 | } 77 | } 78 | } 79 | 80 | void HelpAction::performAction() { 81 | if (_topic != "") { 82 | displayActionHelp(*_parser->createActionWithPrefix(_topic)); 83 | return; 84 | } 85 | 86 | std::ostringstream out; 87 | 88 | out << _parser->helpPreMessage() << '\n'; 89 | 90 | ColumnPrinter printer; 91 | printer.addColumn(false, " "); 92 | printer.addColumn(true, " - "); 93 | 94 | std::vector names; 95 | _parser->pushBackRegisteredActionNames(names); 96 | for (std::vector::const_iterator it = names.begin(); 97 | it != names.end(); ++it) { 98 | std::unique_ptr action(_parser->createActionWithPrefix(*it)); 99 | printer[0] << action->name() << '\n'; 100 | printer[1] << action->shortDescription() << '\n'; 101 | } 102 | printer.print(out); 103 | out << '\n' << _parser->helpPostMessage() << '\n'; 104 | display(out.str()); 105 | } 106 | 107 | const char* HelpAction::staticName() { 108 | return "help"; 109 | } 110 | 111 | const std::string& HelpAction::topic() const { 112 | return _topic; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/mathic/HelpAction.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_HELP_ACTION_GUARD 2 | #define MATHIC_HELP_ACTION_GUARD 3 | 4 | #include "stdinc.h" 5 | #include "Action.h" 6 | #include 7 | 8 | namespace mathic { 9 | class HelpAction : public Action { 10 | public: 11 | HelpAction(); 12 | 13 | virtual void directOptions 14 | (std::vector tokens, CliParser& parser); 15 | virtual void performAction(); 16 | 17 | virtual const char* name() const; 18 | virtual const char* description() const; 19 | virtual const char* shortDescription() const; 20 | virtual void pushBackParameters(std::vector& parameters); 21 | 22 | virtual bool isHelpAction() const {return true;} 23 | 24 | static const char* staticName(); 25 | 26 | protected: 27 | const std::string& topic() const; 28 | 29 | private: 30 | void displayActionHelp(Action& action); 31 | 32 | CliParser* _parser; 33 | std::string _topic; 34 | }; 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/mathic/IntegerParameter.cpp: -------------------------------------------------------------------------------- 1 | #include "IntegerParameter.h" 2 | 3 | #include "error.h" 4 | #include 5 | #include 6 | 7 | namespace mathic { 8 | IntegerParameter::IntegerParameter(const std::string& name, 9 | const std::string& description, 10 | unsigned int defaultValue): 11 | CliParameter(name, description), 12 | _value(defaultValue) { 13 | } 14 | 15 | std::string IntegerParameter::argumentType() const { 16 | return "INTEGER"; 17 | } 18 | 19 | std::string IntegerParameter::valueAsString() const { 20 | std::ostringstream out; 21 | out << value(); 22 | return out.str(); 23 | } 24 | 25 | void IntegerParameter::processArgument(const std::string& argument) { 26 | std::istringstream in(argument); 27 | in >> _value; 28 | std::ostringstream out; 29 | out << _value; 30 | if (out.str() != argument) { 31 | reportError("The value given to option -" + name() + " was not " 32 | "as expected. It must be a non-negative integer in the range " 33 | "[0, 2^31-1]."); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/mathic/IntegerParameter.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_INTEGER_PARAMETER_GUARD 2 | #define MATHIC_INTEGER_PARAMETER_GUARD 3 | 4 | #include "stdinc.h" 5 | #include "CliParameter.h" 6 | #include 7 | #include 8 | 9 | namespace mathic { 10 | class IntegerParameter : public CliParameter { 11 | public: 12 | IntegerParameter(const std::string& name, 13 | const std::string& description, 14 | unsigned int defaultValue); 15 | 16 | unsigned int value() const {return _value;} 17 | void setValue(unsigned int value) {_value = value;} 18 | 19 | operator unsigned int() const {return value();} 20 | void operator=(unsigned int value) {setValue(value);} 21 | 22 | virtual std::string argumentType() const; 23 | virtual std::string valueAsString() const; 24 | virtual void processArgument(const std::string& argument); 25 | 26 | private: 27 | unsigned int _value; 28 | }; 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/mathic/NameFactory.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_NAME_FACTORY_GUARD 2 | #define MATHIC_NAME_FACTORY_GUARD 3 | 4 | #include "stdinc.h" 5 | #include "error.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace mathic { 12 | /** A NameFactory takes a name and then creates an instance of a class 13 | that has been previously registered under that name. This is done 14 | in a general way using templates. 15 | 16 | None of this is very efficient currently. However, the interface can be 17 | implemented much more efficiently if that becomes necessary. 18 | */ 19 | template 20 | class NameFactory { 21 | public: 22 | /** @param abstractName The name for those things that are being 23 | generated in general. Used for error messages. */ 24 | NameFactory(const char* abstractName): _abstractName(abstractName) {} 25 | 26 | typedef std::unique_ptr (*FactoryFunction)(); 27 | void registerProduct(const std::string& name, FactoryFunction function); 28 | 29 | /** Calls the function registered to the parameter name and returns 30 | the result. Returns null if name has not been registered. */ 31 | std::unique_ptr 32 | createNullOnUnknown(const std::string& name) const; 33 | 34 | /** Calls the function registered to the parameter name and returns 35 | the result. Throws an exception if name has not been registered. */ 36 | std::unique_ptr create(const std::string& name) const; 37 | 38 | /** Inserts into names all registered names that have the indicated 39 | prefix in lexicographic increasing order. */ 40 | void namesWithPrefix 41 | (const std::string& prefix, std::vector& names) const; 42 | 43 | /** Returns the name of the kinds of things being created. */ 44 | std::string abstractProductName() const; 45 | 46 | /** Returns true if no names have been registered. */ 47 | bool empty() const; 48 | 49 | private: 50 | typedef std::pair Pair; 51 | typedef typename std::vector::const_iterator const_iterator; 52 | std::vector _pairs; 53 | const std::string _abstractName; 54 | }; 55 | 56 | /** Registers the given name to a function that 57 | default-constructs a ConcreteProduct. */ 58 | template 59 | void nameFactoryRegister 60 | (NameFactory& factory, const std::string& name); 61 | 62 | /** Registers the name ConcreteProduct::staticName() to a function that 63 | default-constructs a ConcreteProduct. */ 64 | template 65 | void nameFactoryRegister 66 | (NameFactory& factory); 67 | 68 | /** Registers the string returned by ConcreteProduct::staticName() 69 | to a function that default-constructs a ConcreteProduct. */ 70 | template 71 | void nameFactoryRegister(NameFactory& factory); 72 | 73 | /** Creates the unique product that has the indicated prefix, or 74 | creates the actual product that has name equal to the indicated 75 | prefix. Exceptions thrown are as for uniqueNamesWithPrefix(). */ 76 | template 77 | std::unique_ptr createWithPrefix 78 | (const NameFactory& factory, const std::string& prefix); 79 | 80 | /** Returns the unique product name that has the indicated prefix, or 81 | return prefix itself if it is the actual name of a product. 82 | 83 | @exception UnknownNameException If no product has the indicated 84 | prefix. 85 | 86 | @exception AmbiguousNameException If more than one product has the 87 | indicated prefix and the prefix is not the actual name of any 88 | product. */ 89 | template 90 | std::string uniqueNameWithPrefix 91 | (const NameFactory& factory, const std::string& prefix); 92 | 93 | 94 | // ************************************************************** 95 | // These implementations have to be included here due 96 | // to being templates. 97 | 98 | template 99 | std::unique_ptr NameFactory:: 100 | createNullOnUnknown(const std::string& name) const { 101 | for (const_iterator it = _pairs.begin(); it != _pairs.end(); ++it) 102 | if (it->first == name) 103 | return it->second(); 104 | return std::unique_ptr(); 105 | } 106 | 107 | template 108 | std::unique_ptr NameFactory:: 109 | create(const std::string& name) const { 110 | std::unique_ptr product = createNullOnUnknown(name); 111 | if (product.get() == 0) 112 | throwError( 113 | "Unknown " + abstractProductName() + " \"" + name + "\"."); 114 | return product; 115 | } 116 | 117 | template 118 | void NameFactory:: 119 | registerProduct(const std::string& name, FactoryFunction function) { 120 | MATHIC_ASSERT(createNullOnUnknown(name).get() == 0); // no duplicate names 121 | _pairs.push_back(Pair(name, function)); 122 | } 123 | 124 | template 125 | void NameFactory::namesWithPrefix( 126 | const std::string& prefix, 127 | std::vector& names 128 | ) const { 129 | for (const_iterator it = _pairs.begin(); it != _pairs.end(); ++it) 130 | if (it->first.compare(0, prefix.size(), prefix) == 0) 131 | names.push_back(it->first); 132 | std::sort(names.begin(), names.end()); 133 | } 134 | 135 | template 136 | bool NameFactory::empty() const { 137 | return _pairs.empty(); 138 | } 139 | 140 | template 141 | std::string NameFactory::abstractProductName() const { 142 | return _abstractName; 143 | } 144 | 145 | template 146 | void nameFactoryRegister(NameFactory& factory) { 147 | nameFactoryRegister 148 | (factory, ConcreteProduct::staticName()); 149 | } 150 | 151 | template 152 | void nameFactoryRegister 153 | (NameFactory& factory, const std::string& name) { 154 | // work-around for no local functions in old C++ 155 | struct HoldsFunction { 156 | static std::unique_ptr createConcreteProduct() { 157 | return std::unique_ptr(new ConcreteProduct()); 158 | } 159 | }; 160 | factory.registerProduct(name, HoldsFunction::createConcreteProduct); 161 | } 162 | 163 | template 164 | std::unique_ptr createWithPrefix 165 | (const NameFactory& factory, const std::string& prefix) { 166 | return factory.createNullOnUnknown(uniqueNameWithPrefix(factory, prefix)); 167 | } 168 | 169 | template 170 | std::string uniqueNameWithPrefix 171 | (const NameFactory& factory, const std::string& prefix) { 172 | std::vector names; 173 | factory.namesWithPrefix(prefix, names); 174 | 175 | // if exact string found, then use that one even if there are other 176 | // prefix matches. 177 | if (std::find(names.begin(), names.end(), prefix) != names.end()) { 178 | names.clear(); 179 | names.push_back(prefix); 180 | } 181 | 182 | if (names.empty()) { 183 | throwError 184 | ("No " + factory.abstractProductName() + 185 | " has the prefix \"" + prefix + "\"."); 186 | } 187 | 188 | if (names.size() >= 2) { 189 | std::string errorMsg = "More than one " + factory.abstractProductName() + 190 | " has prefix \"" + prefix + "\":\n "; 191 | for (size_t name = 0; name < names.size(); ++name) 192 | errorMsg += ' ' + names[name]; 193 | throwError(errorMsg); 194 | } 195 | 196 | MATHIC_ASSERT(names.size() == 1); 197 | return names.back(); 198 | } 199 | } 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /src/mathic/StlSet.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_STL_SET_GUARD 2 | #define MATHIC_STL_SET_GUARD 3 | 4 | #include "stdinc.h" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace mathic { 10 | template 11 | class StlSet { 12 | public: 13 | typedef C Configuration; 14 | typedef typename Configuration::Entry Entry; 15 | 16 | StlSet(const Configuration& configuration): 17 | _conf(configuration), _set(Cmp(&_conf)) {} 18 | Configuration& getConfiguration() {return _conf;} 19 | const Configuration& getConfiguration() const {return _conf;} 20 | 21 | std::string getName() const {return "stlset";} 22 | void push(Entry entry) {_set.insert(entry);} 23 | void push(const Entry* begin, const Entry* end) { 24 | for (; begin != end; ++begin) 25 | push(*begin); 26 | } 27 | Entry pop() { 28 | Entry top = *_set.begin(); 29 | _set.erase(_set.begin()); 30 | return top; 31 | } 32 | Entry top() { 33 | return *_set.begin(); 34 | } 35 | bool empty() const {return _set.empty();} 36 | void print(std::ostream& out) const { 37 | out << getName() << ":\n"; 38 | for (typename std::multiset::const_iterator it = _set.begin(); 39 | it != _set.end(); ++it) 40 | out << ' ' << *it; 41 | out << '\n'; 42 | } 43 | 44 | /** This is necessarily an estimate since there is no 45 | way to tell how much memory a std::multiset is using. */ 46 | size_t getMemoryUse() const { 47 | const size_t bytesPerItemEstimate = 48 | 2 * sizeof(void*) + // assume binary tree with left and right pointers 49 | sizeof(void*) + // assume minimal overhead in the allocator behind new 50 | sizeof(int) + // assume some overhead to maintain balance in tree 51 | sizeof(Entry); // assume data payload 52 | return _set.size() * bytesPerItemEstimate; 53 | } 54 | 55 | private: 56 | Configuration _conf; 57 | struct Cmp { 58 | Cmp(const Configuration* conf): _conf(conf) {} 59 | bool operator()(const Entry& a, const Entry& b) { 60 | return _conf->cmpLessThan(_conf->compare(b, a)); 61 | } 62 | const Configuration* _conf; // should be &, but gcc complains 63 | }; 64 | std::multiset _set; 65 | }; 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/mathic/StringParameter.cpp: -------------------------------------------------------------------------------- 1 | #include "StringParameter.h" 2 | 3 | namespace mathic { 4 | StringParameter::StringParameter(const std::string& name, 5 | const std::string& description, 6 | const std::string& defaultValue): 7 | CliParameter(name, description), 8 | _value(defaultValue) { 9 | } 10 | 11 | std::string StringParameter::argumentType() const { 12 | return "STRING"; 13 | } 14 | 15 | std::string StringParameter::valueAsString() const { 16 | return _value; 17 | } 18 | 19 | void StringParameter::processArgument(const std::string& argument) { 20 | _value = argument; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/mathic/StringParameter.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_STRING_PARAMETER_GUARD 2 | #define MATHIC_STRING_PARAMETER_GUARD 3 | 4 | #include "stdinc.h" 5 | #include "CliParameter.h" 6 | #include 7 | #include 8 | 9 | namespace mathic { 10 | class StringParameter : public CliParameter { 11 | public: 12 | StringParameter(const std::string& name, 13 | const std::string& description, 14 | const std::string& defaultValue); 15 | 16 | const std::string& value() const {return _value;} 17 | void setValue(const std::string& value) {_value = value;} 18 | 19 | operator const std::string&() const {return value();} 20 | void operator=(const std::string& value) {setValue(value);} 21 | bool operator==(const std::string& str) const {return value() == str;} 22 | 23 | virtual std::string argumentType() const; 24 | virtual std::string valueAsString() const; 25 | virtual void processArgument(const std::string& argument); 26 | 27 | private: 28 | std::string _value; 29 | }; 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/mathic/Timer.cpp: -------------------------------------------------------------------------------- 1 | #include "Timer.h" 2 | 3 | namespace mathic { 4 | unsigned long Timer::getMilliseconds() const { 5 | const double floatSpan = clock() - _clocksAtReset; 6 | const double floatMilliseconds = 1000 * (floatSpan / CLOCKS_PER_SEC); 7 | unsigned long milliseconds = static_cast(floatMilliseconds); 8 | if (floatMilliseconds - milliseconds >= 0.5) 9 | ++milliseconds; 10 | return milliseconds; 11 | } 12 | 13 | void Timer::print(FILE* out) const { 14 | unsigned long milliseconds = getMilliseconds(); 15 | unsigned long seconds = milliseconds / 1000; 16 | unsigned long minutes = seconds / 60; 17 | unsigned long hours = minutes / 60; 18 | 19 | milliseconds %= 1000; 20 | seconds %= 60; 21 | minutes %= 60; 22 | 23 | fputc('(', out); 24 | if (hours != 0) 25 | fprintf(out, "%luh", hours); 26 | if (minutes != 0 || hours != 0) 27 | fprintf(out, "%lum", minutes); 28 | fprintf(out, "%lu.%03lus)", seconds, milliseconds); 29 | } 30 | 31 | void Timer::print(std::ostream& out) const { 32 | unsigned long milliseconds = getMilliseconds(); 33 | unsigned long seconds = milliseconds / 1000; 34 | unsigned long minutes = seconds / 60; 35 | unsigned long hours = minutes / 60; 36 | 37 | milliseconds %= 1000; 38 | seconds %= 60; 39 | minutes %= 60; 40 | 41 | if (hours != 0) 42 | out << hours << 'h'; 43 | if (minutes != 0 || hours != 0) 44 | out << minutes << 'm'; 45 | out << seconds << '.'; 46 | out << (milliseconds / 100); 47 | out << ((milliseconds / 10) % 10); 48 | out << (milliseconds % 10); 49 | out << "s"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/mathic/Timer.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_TIMER_GUARD 2 | #define MATHIC_TIMER_GUARD 3 | 4 | #include "stdinc.h" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace mathic { 10 | /** Measures spans of CPU time. 11 | 12 | The internal record of time can overflow quickly. If 13 | clock_t is 32 bits unsigned and CLOCKS_PER_TIC is one million 14 | then overflow will occur after 71 minutes. */ 15 | class Timer { 16 | public: 17 | Timer() {reset();} 18 | 19 | /** Resets the amount of elapsed CPU time to zero. */ 20 | void reset() {_clocksAtReset = std::clock();} 21 | 22 | /** Returns the number of CPU milliseconds since the last reset. 23 | See class description for time span overflow limitations. */ 24 | unsigned long getMilliseconds() const; 25 | 26 | /** Prints the elapsed time in a human readable format. See 27 | class description for time span overflow limitations. */ 28 | void print(FILE* out) const; 29 | 30 | /** Prints the elapsed time in a human readable format. See 31 | class description for time span overflow limitations. */ 32 | void print(std::ostream& out) const; 33 | 34 | private: 35 | std::clock_t _clocksAtReset; 36 | }; 37 | 38 | inline std::ostream& operator<<(std::ostream& out, const Timer& timer) { 39 | timer.print(out); 40 | return out; 41 | } 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/mathic/TourTree.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_TOUR_TREE_GUARD 2 | #define MATHIC_TOUR_TREE_GUARD 3 | 4 | #include "stdinc.h" 5 | #include "ComTree.h" 6 | #include 7 | #include 8 | 9 | namespace mathic { 10 | class TourTreeSuggestedOptions { 11 | public: 12 | // there are no tournament tree options so far. 13 | }; 14 | 15 | template 16 | class TourTree { 17 | public: 18 | typedef C Configuration; 19 | typedef typename Configuration::Entry Entry; 20 | 21 | TourTree(const Configuration& configuration); 22 | Configuration& getConfiguration() {return _conf;} 23 | const Configuration& getConfiguration() const {return _conf;} 24 | 25 | std::string getName() const; 26 | void push(Entry entry); 27 | template 28 | void push(It begin, It end); 29 | Entry pop(); 30 | Entry top() const; 31 | bool empty() const {return _tree.empty();} 32 | void print(std::ostream& out) const; 33 | 34 | void decreaseTop(Entry newEntry); 35 | 36 | template 37 | void forAll(T& t) const { 38 | typedef typename std::vector::const_iterator Iter; 39 | Iter end = _players.end(); 40 | for (Iter it = _players.begin(); it != end; ++it) 41 | if (!t.proceed(it->entry)) 42 | return; 43 | } 44 | 45 | template 46 | void forAll(T& t) { 47 | typedef typename std::vector::iterator Iter; 48 | Iter end = _players.end(); 49 | for (Iter it = _players.begin(); it != end; ++it) 50 | if (!t.proceed(it->entry)) 51 | return; 52 | } 53 | 54 | void clear(); 55 | 56 | size_t getMemoryUse() const; 57 | 58 | private: 59 | class Player; 60 | // Setting fastIndex to true speeds up left/right child 61 | // computations. We only compute parents, so there is no reason 62 | // to enable fastIndex. 63 | typedef ComTree Tree; 64 | typedef typename Tree::Node Node; 65 | struct Player { 66 | Player(const Entry& entry, Node leaf): entry(entry), leaf(leaf) {} 67 | Entry entry; 68 | Node leaf; 69 | }; 70 | 71 | void reallocate(); 72 | 73 | /// Asserts internal invariants if asserts are turned on. 74 | bool isValid() const; 75 | 76 | Tree _tree; 77 | std::vector _players; 78 | Configuration _conf; 79 | }; 80 | 81 | template 82 | void TourTree::clear() { 83 | MATHIC_ASSERT(isValid()); 84 | _tree.clear(); 85 | _players.clear(); 86 | MATHIC_ASSERT(isValid()); 87 | } 88 | 89 | template 90 | size_t TourTree::getMemoryUse() const { 91 | return _tree.getMemoryUse() + 92 | _players.capacity() * sizeof(_players.front()); 93 | } 94 | 95 | template 96 | TourTree::TourTree(const C& configuration): _conf(configuration) { 97 | reallocate(); 98 | } 99 | 100 | template 101 | std::string TourTree::getName() const { 102 | return std::string("t-tree (") + 103 | (C::fastIndex ? "fi" : "si") + 104 | ')'; 105 | } 106 | 107 | template 108 | void TourTree::push(Entry entry) { 109 | MATHIC_SLOW_ASSERT(isValid()); 110 | if (!_tree.hasFreeCapacity(2)) 111 | reallocate(); 112 | if (empty()) { 113 | _players.push_back(Player(entry, Node())); 114 | _tree.pushBackWithCapacity(&_players.back()); 115 | MATHIC_SLOW_ASSERT(isValid()); 116 | return; 117 | } 118 | // move leaf down as left child 119 | Node posParent = _tree.lastLeaf().next().parent(); 120 | Player* moveDown = _tree[posParent]; 121 | _tree.pushBackWithCapacity(moveDown); 122 | moveDown->leaf = _tree.lastLeaf(); 123 | MATHIC_ASSERT(_tree.lastLeaf().isLeft()); 124 | 125 | // insert entry as right child 126 | _players.push_back(Player(entry, _tree.lastLeaf().next())); 127 | _tree.pushBackWithCapacity(&_players.back()); 128 | MATHIC_ASSERT(_tree.lastLeaf().isRight()); 129 | 130 | Node pos = _tree.lastLeaf(); 131 | do { 132 | MATHIC_ASSERT(!pos.isRoot()); 133 | MATHIC_ASSERT(posParent == pos.parent()); 134 | typename C::CompareResult cmp = _conf.compare 135 | (_tree[posParent]->entry, _tree[pos]->entry); 136 | if (!_conf.cmpLessThan(cmp)) 137 | break; 138 | _tree[posParent] = _tree[pos]; 139 | pos = posParent; 140 | posParent = pos.parent(); 141 | } while (!pos.isRoot()); 142 | MATHIC_SLOW_ASSERT(isValid()); 143 | } 144 | 145 | template 146 | template 147 | void TourTree::push(It begin, It end) { 148 | for (; begin != end; ++begin) 149 | push(*begin); 150 | } 151 | 152 | template 153 | void TourTree::decreaseTop(Entry newEntry) { 154 | MATHIC_ASSERT(!empty()); 155 | Player* player = _tree[Node()]; 156 | player->entry = newEntry; 157 | for (Node pos = player->leaf; !pos.isRoot(); pos = pos.parent()) { 158 | Player* opponent = _tree[pos.sibling()]; 159 | if (_conf.cmpLessThan(_conf.compare(player->entry, opponent->entry))) 160 | player = opponent; 161 | _tree[pos.parent()] = player; 162 | } 163 | MATHIC_SLOW_ASSERT(isValid()); 164 | } 165 | 166 | template 167 | typename TourTree::Entry TourTree::pop() { 168 | MATHIC_ASSERT(!empty()); 169 | Entry top = _tree[Node()]->entry; 170 | if (_tree.lastLeaf().isRoot()) { 171 | _tree.popBack(); 172 | _players.pop_back(); 173 | MATHIC_SLOW_ASSERT(isValid()); 174 | return top; 175 | } 176 | Node parentPos = _tree.lastLeaf().parent(); 177 | Player* left = _tree[_tree.lastLeaf().prev()]; 178 | Player* right = _tree[_tree.lastLeaf()]; 179 | 180 | if (right == _tree[parentPos]) { 181 | // we want right to be the smaller entry so that it can be 182 | // removed without that having an impact further up the tree. 183 | std::swap(left->entry, right->entry); 184 | for (Node pos = parentPos; _tree[pos] == right; pos = pos.parent()) { 185 | _tree[pos] = left; 186 | if (pos.isRoot()) 187 | break; 188 | } 189 | } 190 | Player* player = _tree[Node()]; 191 | player->entry = right->entry; // let right take the winner's place 192 | MATHIC_ASSERT(right == &_players.back()); 193 | _players.pop_back(); // remove right 194 | left->leaf = parentPos; // move up left 195 | _tree.popBack(); 196 | _tree.popBack(); 197 | for (Node pos = player->leaf; !pos.isRoot();) { 198 | Player* opponent = _tree[pos.sibling()]; 199 | typename C::CompareResult cmp = 200 | _conf.compare(player->entry, opponent->entry); 201 | if (_conf.cmpLessThan(cmp)) 202 | player = opponent; 203 | pos = pos.parent(); 204 | _tree[pos] = player; 205 | } 206 | MATHIC_SLOW_ASSERT(isValid()); 207 | return top; 208 | } 209 | 210 | template 211 | typename TourTree::Entry TourTree::top() const { 212 | MATHIC_ASSERT(!empty()); 213 | return _tree[Node()]->entry; 214 | } 215 | 216 | template 217 | void TourTree::print(std::ostream& out) const { 218 | out << getName() << ": {\n" << _tree << "}\n"; 219 | } 220 | 221 | template 222 | void TourTree::reallocate() { 223 | MATHIC_ASSERT(isValid()); 224 | _tree.increaseCapacity(); 225 | const size_t newCapacity = _tree.capacity(); 226 | if (_players.empty()) 227 | _players.reserve(newCapacity / 2 + 2); 228 | else { 229 | Player* oldBegin = &_players.front(); 230 | _players.reserve(newCapacity / 2 + 2); 231 | Player* newBegin = &_players.front(); 232 | for (Node pos; pos <= _tree.lastLeaf(); ++pos) 233 | _tree[pos] = newBegin + (_tree[pos] - oldBegin); 234 | } 235 | MATHIC_ASSERT(isValid()); 236 | } 237 | 238 | template 239 | bool TourTree::isValid() const { 240 | #ifndef MATHIC_DEBUG 241 | return true; 242 | #else 243 | MATHIC_ASSERT 244 | ((_tree.empty() && _players.empty()) || // just constructed 245 | (_tree.capacity() + 1 <= 2 * _players.capacity())); 246 | MATHIC_ASSERT((empty() && _players.empty()) || 247 | (_tree.size() + 1 == 2 * _players.size())); 248 | // _tree points into _players 249 | for (Node pos; pos <= _tree.lastLeaf(); ++pos) { 250 | size_t index = _tree[pos] - &(_players.front()); 251 | MATHIC_ASSERT(index < _players.size()); 252 | } 253 | 254 | for (Node pos; pos <= _tree.lastLeaf(); ++pos) { 255 | if (pos.left() >= _tree.lastLeaf()) { // leaf or two children 256 | MATHIC_ASSERT(pos.right() > _tree.lastLeaf()); // pos is a leaf 257 | MATHIC_ASSERT(_tree[pos]->leaf == pos); 258 | } else { 259 | MATHIC_ASSERT(pos.right() <= _tree.lastLeaf()); // pos has two children 260 | // exactly one child wins 261 | MATHIC_ASSERT(_tree[pos.left()] != _tree[pos.right()]); 262 | MATHIC_ASSERT(_tree[pos] == _tree[pos.left()] || 263 | _tree[pos] == _tree[pos.right()]); 264 | MATHIC_ASSERT(!_conf.cmpLessThan( 265 | _conf.compare(_tree[pos]->entry, _tree[pos.left()]->entry))); 266 | MATHIC_ASSERT(!_conf.cmpLessThan( 267 | _conf.compare(_tree[pos]->entry, _tree[pos.right()]->entry))); 268 | } 269 | } 270 | return true; 271 | #endif 272 | } 273 | } 274 | 275 | #endif 276 | -------------------------------------------------------------------------------- /src/mathic/display.cpp: -------------------------------------------------------------------------------- 1 | #include "display.h" 2 | 3 | #include 4 | #include 5 | 6 | namespace mathic { 7 | namespace { 8 | /** Automatically break lines at this width. */ 9 | static const size_t ConsoleWidth = 79; 10 | 11 | /** Helper class for display(). */ 12 | class Printer { 13 | public: 14 | Printer(const std::string& msg, const std::string& prepend): 15 | _pos(0), _lineSize(0), _msg(msg), _prefix(prepend) { 16 | 17 | std::string wordSpacePrefix; 18 | 19 | while (_pos < _msg.size()) { 20 | // We are always at the start of a line at this point. 21 | MATHIC_ASSERT(_lineSize == 0); 22 | readIndentation(); 23 | printRaw(_prefix); 24 | printRaw(_indentation); 25 | 26 | if (_pos == _msg.size()) 27 | break; 28 | if (_msg[_pos] == '\n') { 29 | newLine(); 30 | ++_pos; 31 | continue; 32 | } 33 | 34 | wordSpacePrefix.clear(); 35 | while (_pos < _msg.size()) { 36 | if (_msg[_pos] == '\n') { 37 | ++_pos; 38 | break; 39 | } 40 | if (isspace(_msg[_pos])) { 41 | wordSpacePrefix += _msg[_pos]; 42 | ++_pos; 43 | continue; 44 | } 45 | MATHIC_ASSERT(!isspace(_msg[_pos])); 46 | MATHIC_ASSERT(_msg[_pos] != '\n'); 47 | MATHIC_ASSERT(_pos < _msg.size()); 48 | 49 | std::string word; 50 | while (_pos < _msg.size() && 51 | _msg[_pos] != '\n' && 52 | !isspace(_msg[_pos])) { 53 | word += _msg[_pos]; 54 | ++_pos; 55 | } 56 | MATHIC_ASSERT(!word.empty()); 57 | printWord(wordSpacePrefix, word); 58 | wordSpacePrefix.clear(); 59 | } 60 | 61 | newLine(); 62 | } 63 | } 64 | 65 | private: 66 | void newLine() { 67 | printRaw('\n'); 68 | _lineSize = 0; 69 | } 70 | 71 | void readIndentation() { 72 | // Read whitespace at beginning of line. 73 | _indentation.clear(); 74 | while (_pos < _msg.size() && _msg[_pos] != '\n' && isspace(_msg[_pos])) { 75 | _indentation += _msg[_pos]; 76 | ++_pos; 77 | } 78 | } 79 | 80 | void printWord(const std::string& wordSpacePrefix, const std::string& word) { 81 | MATHIC_ASSERT(!word.empty()); 82 | 83 | // Note that this will print beyond the console width if word is 84 | // the first thing we are printing on this line. That is because 85 | // there then is no way to fit the word on one line. 86 | size_t wordAndPrefixSize = word.size() + wordSpacePrefix.size(); 87 | if (_lineSize != 0 && _lineSize + wordAndPrefixSize > ConsoleWidth) { 88 | // we skip space before word if inserting newline 89 | newLine(); 90 | printRaw(_prefix); 91 | printRaw(_indentation); 92 | } else 93 | printRaw(wordSpacePrefix); 94 | printRaw(word); 95 | } 96 | 97 | void printRaw(const std::string& word) { 98 | fputs(word.c_str(), stderr); 99 | _lineSize += word.size(); 100 | } 101 | 102 | void printRaw(char c) { 103 | fputc(c, stderr); 104 | ++_lineSize; 105 | } 106 | 107 | size_t _pos; 108 | size_t _lineSize; 109 | const std::string& _msg; 110 | const std::string& _prefix; 111 | std::string _indentation; 112 | }; 113 | } 114 | 115 | void display(const std::string& msg, const std::string& prepend) { 116 | Printer(msg, prepend); 117 | } 118 | 119 | void displayNote(const std::string& msg) { 120 | display("NOTE: " + msg + "\n"); 121 | } 122 | 123 | void displayError(const std::string& msg) { 124 | display("ERROR: " + msg + "\n"); 125 | } 126 | 127 | void displayInternalError(const std::string& msg) { 128 | display("INTERNAL ERROR: " + msg + "\n"); 129 | } 130 | 131 | void displayException(const std::exception& exception) { 132 | try { 133 | display(exception.what()); 134 | } catch (...) { 135 | fputs("\n\n*** Error while printing error! ***\n", stderr); 136 | fflush(stderr); 137 | fputs("*** Retrying display of error using simpler display method. ***\n", 138 | stderr); 139 | fflush(stderr); 140 | fputs(exception.what(), stderr); 141 | fflush(stderr); 142 | throw; 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/mathic/display.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_DISPLAY_GUARD 2 | #define MATHIC_DISPLAY_GUARD 3 | 4 | #include 5 | #include "stdinc.h" 6 | 7 | /** @file display.h 8 | 9 | This file contains functions for printing strings to standard 10 | error. They all perform automatic line breaking suitable for printing 11 | to a console. 12 | */ 13 | 14 | namespace mathic { 15 | /** Display msg to standard error with automatic line breaking. If a 16 | automatically broken line begins with whitespace, that whitespace is 17 | repeated in front of every line that is generated from breaking 18 | it. 19 | 20 | @param prepend Print this in front of every line that is printed. 21 | */ 22 | void display(const std::string& msg, const std::string& prepend = ""); 23 | 24 | /** Display msg to standard error in a way that indicates that this is 25 | something that the user should take note of but that is not an 26 | error. */ 27 | void displayNote(const std::string& msg); 28 | 29 | /** Display msg to standard error in a way that indicates that it is 30 | an error. */ 31 | void displayError(const std::string& msg); 32 | 33 | /** Display msg to standard in a way that indicates that it is an 34 | internal error. */ 35 | void displayInternalError(const std::string& errorMsg); 36 | 37 | /** Display the message of exception. */ 38 | void displayException(const std::exception& exception); 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/mathic/error.cpp: -------------------------------------------------------------------------------- 1 | #include "error.h" 2 | #include 3 | 4 | namespace mathic { 5 | void reportError(const std::string& errorMsg) { 6 | throw MathicException("ERROR: " + errorMsg); 7 | } 8 | 9 | void reportInternalError(const std::string& errorMsg) { 10 | throw InternalMathicException("INTERNAL ERROR: " + errorMsg); 11 | } 12 | 13 | void reportInternalError 14 | (const std::string& errorMsg, const char* file, unsigned int lineNumber) { 15 | 16 | std::ostringstream err; 17 | err << errorMsg << '\n' 18 | << "The internal error occured in file " << file 19 | << " on line " << lineNumber << '.'; 20 | reportInternalError(err.str()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/mathic/error.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_ERROR_GUARD 2 | #define MATHIC_ERROR_GUARD 3 | 4 | #include 5 | #include 6 | 7 | namespace mathic { 8 | /** This is the base of the Mathic exception hierarchy for exceptions 9 | that can occur due to expected error conditions. */ 10 | class MathicException : public std::runtime_error { 11 | public: 12 | MathicException(const std::string& str): runtime_error(str) {} 13 | }; 14 | 15 | /** This exception signals that a bug in Mathic has been detected. */ 16 | class InternalMathicException : public std::logic_error { 17 | public: 18 | InternalMathicException(const std::string& str): logic_error(str) {} 19 | }; 20 | 21 | // The do {...} while (0) is to collect everything into a single 22 | // statement that still requires a semicolon after it. The throw is to 23 | // prevent spurious compiler warnings about a missing return 24 | // statement. 25 | #define MATHIC_INTERNAL_ERROR(msg) \ 26 | do { \ 27 | reportInternalError(msg, __FILE__, __LINE__); \ 28 | throw; \ 29 | } while (false) 30 | #define INTERNAL_ERROR_UNIMPLEMENTED() \ 31 | INTERNAL_ERROR("Called function that has not been implemented.") 32 | 33 | // These methods throw exceptions. 34 | void reportError(const std::string& errorMsg); 35 | void reportInternalError(const std::string& errorMsg); 36 | void reportInternalError 37 | (const std::string& errorMsg, const char* file, unsigned int lineNumber); 38 | 39 | template 40 | void throwError(const std::string& errorMsg) { 41 | throw Exception("ERROR: " + errorMsg + '\n'); 42 | } 43 | 44 | 45 | #define MATHIC_DEFINE_EXCEPTION(NAME) \ 46 | class NAME##Exception : public MathicException { \ 47 | public: \ 48 | NAME##Exception(const std::string& str): MathicException(str) {} \ 49 | } 50 | 51 | MATHIC_DEFINE_EXCEPTION(UnknownName); 52 | MATHIC_DEFINE_EXCEPTION(AmbiguousName); 53 | MATHIC_DEFINE_EXCEPTION(Unsupported); 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/mathic/main.cpp: -------------------------------------------------------------------------------- 1 | #include "divsim/divMain.h" 2 | #include "pqsim/pqMain.h" 3 | #include 4 | #include 5 | 6 | int main(int argc, const char** args) { 7 | std::string name = args[0]; 8 | const size_t offset = name.find_last_of("/\\"); 9 | if (offset != std::string::npos) 10 | name = name.substr(offset + 1); 11 | if (name == "div") 12 | return divMain(); 13 | else if (name == "pq") 14 | return pqMain(argc, args); 15 | std::cout << "Name of executable must be div or pq.\n"; 16 | return 1; 17 | } 18 | -------------------------------------------------------------------------------- /src/mathic/stdinc.h: -------------------------------------------------------------------------------- 1 | #ifndef MATHIC_STDINC_GUARD 2 | #define MATHIC_STDINC_GUARD 3 | 4 | #ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++. 5 | // Sometimes you know that a function will be called very rarely so you want to 6 | // tell the compiler not to inline it even if it could be inlined at only a 7 | // modest increase in code size. That is what MATHIC_NO_INLINE does. 8 | #define MATHIC_NO_INLINE __declspec(noinline) 9 | 10 | // Sometimes the compiler just will not inline functions that should 11 | // be inlined. Use sparingly --- preferably only if a profiler says 12 | // that a tiny often-called function consumes a significant amount of time. 13 | #define MATHIC_INLINE __forceinline 14 | 15 | // Tells the compiler to always assume that the expression X is true. 16 | #define MATHIC_ASSUME(X) __assume(X) 17 | 18 | // As MATHIC_ASSUME, but might actually evaluate X at run-time if it has 19 | // side-effects. The point is that this can be used on compilers with no other 20 | // support for assuming things. So there is no difference on MS VC++. 21 | #define MATHIC_ASSUME_AND_MAY_EVALUATE(X) __assume(X) 22 | 23 | // Tells the compiler that this function returns a pointer that is not an alias 24 | // for any other point that is currently valid in the program - like malloc. 25 | #define MATHIC_RETURN_NO_ALIAS __declspec(restrict) 26 | 27 | // Tells the compiler that this function will never throw an exception. 28 | #define MATHIC_NOTHROW __declspec(nothrow) 29 | 30 | // Tells the compiler that this function has no effects except the return value 31 | // and the return value depends only on the arguments and first-level 32 | // indirections of the arguments. (this is the common denominator of GCC 33 | // and MS VC++ capabilities) 34 | #define MATHIC_PURE __declspec(noalias) 35 | 36 | // Tells the compiler that the return value of this function must be looked 37 | // at by the caller. For example this is appropriate for realloc. 38 | #define MATHIC_MUST_CHECK_RETURN_VALUE 39 | 40 | // Tells the compiler that the current line of code cannot be reached. 41 | #define MATHIC_UNREACHABLE __assume(false) 42 | 43 | // Tells the compiler that a variable that is a pointer (not a reference) 44 | // does not alias any other pointer that is used in the current scope. 45 | #define MATHIC_RESTRICT __restrict 46 | 47 | #elif defined (__GNUC__) // GCC compiler 48 | 49 | #define MATHIC_NO_INLINE __attribute__((noinline)) 50 | #define MATHIC_INLINE __attribute__((always_inline)) inline 51 | #define MATHIC_ASSUME(X) 52 | #define MATHIC_ASSUME_AND_MAY_EVALUATE(X) do {if(!(X)){MATHIC_UNREACHABLE;}while(0)} 53 | #define MATHIC_RETURN_NO_ALIAS __attribute__(malloc) 54 | #define MATHIC_NOTHROW __attribute__(nothrow) 55 | #define MATHIC_PURE __attribute__(pure) 56 | #define MATHIC_MUST_CHECK_RETURN_VALUE __attribute__(warn_unused_result) 57 | #define MATHIC_UNREACHABLE __builtin_unreachable() 58 | 59 | #else 60 | 61 | #define MATHIC_NO_INLINE 62 | #define MATHIC_INLINE inline 63 | #define MATHIC_ASSUME(X) 64 | #define MATHIC_ASSUME_AND_MAY_EVALUATE(X) 65 | #define MATHIC_RETURN_NO_ALIAS 66 | #define MATHIC_NOTHROW 67 | #define MATHIC_PURE 68 | #define MATHIC_MUST_CHECK_RETURN_VALUE 69 | #define MATHIC_UNREACHABLE 70 | 71 | #endif 72 | 73 | 74 | #ifdef MATHIC_SLOW_DEBUG 75 | // for asserts that take a long time. 76 | #define MATHIC_SLOW_ASSERT(X) MATHIC_ASSERT(X) 77 | #ifndef MATHIC_DEBUG 78 | #define MATHIC_DEBUG 79 | #endif 80 | #else 81 | #define MATHIC_SLOW_ASSERT(X) 82 | #endif 83 | 84 | #ifdef MATHIC_DEBUG 85 | #include 86 | #define MATHIC_ASSERT(X) do{assert(X);}while(0) 87 | #define MATHIC_ASSERT_NO_ASSUME(X) MATHIC_ASSERT(X) 88 | #else 89 | #define MATHIC_ASSERT(X) MATHIC_ASSUME(X) 90 | #define MATHIC_ASSERT_NO_ASSUME(X) 91 | #endif 92 | 93 | namespace mathic { 94 | static unsigned long const BitsPerByte = 8; 95 | } 96 | 97 | #ifndef MATHIC_NO_MIC_NAMESPACE 98 | namespace mic { 99 | using namespace mathic; 100 | } 101 | #endif 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /src/pqsim/GeobucketModel.h: -------------------------------------------------------------------------------- 1 | #ifndef GEOBUCKET_MODEL_GUARD 2 | #define GEOBUCKET_MODEL_GUARD 3 | 4 | #include "Model.h" 5 | #include "mathic/Geobucket.h" 6 | 7 | template< 8 | bool TrackFront, 9 | bool MinBucketBinarySearch, 10 | bool Premerge, 11 | bool CollectMax, 12 | int BucketStorage, 13 | size_t InsertFactor> 14 | class GeobucketModelBase { 15 | public: 16 | GeobucketModelBase(size_t geoBase, size_t minBucketSize): 17 | geoBase(geoBase), minBucketSize(minBucketSize) {} 18 | size_t geoBase; 19 | size_t minBucketSize; 20 | 21 | static const bool trackFront = TrackFront; 22 | static const bool minBucketBinarySearch = MinBucketBinarySearch; 23 | static const bool premerge = Premerge; 24 | static const bool collectMax = CollectMax; 25 | static const mathic::GeobucketBucketStorage bucketStorage = 26 | (mathic::GeobucketBucketStorage)BucketStorage; 27 | static const size_t insertFactor = InsertFactor; 28 | }; 29 | 30 | template< 31 | bool OnSpans, 32 | bool TrackFront, 33 | bool MinBucketBinarySearch, 34 | bool Deduplicate, 35 | bool Premerge, 36 | bool CollectMax, 37 | int BucketStorage, 38 | size_t InsertFactor = 1> 39 | class GeobucketModel : 40 | public Model< 41 | OnSpans, 42 | Deduplicate, 43 | false, 44 | mathic::Geobucket, 45 | GeobucketModelBase< 46 | TrackFront, 47 | MinBucketBinarySearch, 48 | Premerge, 49 | CollectMax, 50 | BucketStorage, 51 | InsertFactor> > { 52 | public: 53 | GeobucketModel(size_t geoBase, size_t minBucketSize): 54 | Model< 55 | OnSpans, 56 | Deduplicate, 57 | false, 58 | mathic::Geobucket, 59 | GeobucketModelBase< 60 | TrackFront, 61 | MinBucketBinarySearch, 62 | Premerge, 63 | CollectMax, 64 | BucketStorage, 65 | InsertFactor> >(geoBase, minBucketSize) {} 66 | }; 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/pqsim/HeapModel.h: -------------------------------------------------------------------------------- 1 | #ifndef HEAP_MODEL_GUARD 2 | #define HEAP_MODEL_GUARD 3 | 4 | #include "Model.h" 5 | #include "mathic/Heap.h" 6 | 7 | template 8 | struct HeapModelBase { 9 | static const bool fastIndex = FastIndex; 10 | }; 11 | 12 | template 13 | class HeapModel : public Model< 14 | OnSpans, Deduplicate, true, mathic::Heap, HeapModelBase > {}; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/pqsim/Item.cpp: -------------------------------------------------------------------------------- 1 | #include "stdinc.h" 2 | #include "Item.h" 3 | 4 | void Item::print(std::ostream& out) const { 5 | if (atEnd()) 6 | out << "invalid"; 7 | else 8 | out << getValue(); 9 | } 10 | -------------------------------------------------------------------------------- /src/pqsim/Item.h: -------------------------------------------------------------------------------- 1 | #ifndef ITEM_GUARD 2 | #define ITEM_GUARD 3 | 4 | #include 5 | #include 6 | 7 | typedef unsigned long Value; 8 | 9 | class Item; 10 | enum CompareResult {Less, Equal, Greater}; 11 | CompareResult compare(Value a, Value b); 12 | CompareResult compare(const Item& a, const Item& b); 13 | 14 | class Item { 15 | public: 16 | Item(); // creates Item which is at end. 17 | explicit Item(Value value); 18 | Item(const Value* begin, const Value* end); 19 | 20 | bool atEnd() const; 21 | void toNext(); 22 | Item getNext() const; 23 | size_t getLength() const; 24 | 25 | const Value* begin() const {return _current;} 26 | const Value* end() const {return _end;} 27 | 28 | Value getValue() const; 29 | 30 | void print(std::ostream& out) const; 31 | 32 | bool operator==(const Item& item); 33 | 34 | private: 35 | Value _value; 36 | const Value* _current; 37 | const Value* _end; 38 | Value dummy; // to make sizeof(Item) a power of two 39 | }; 40 | 41 | template struct ItemOrValue{}; 42 | template<> struct ItemOrValue {typedef Item Entry;}; 43 | template<> struct ItemOrValue {typedef Value Entry;}; 44 | 45 | inline CompareResult compare(Value a, Value b) { 46 | if (a < b) 47 | return Less; 48 | if (b < a) 49 | return Greater; 50 | return Equal; 51 | } 52 | 53 | inline CompareResult compare(const Item& a, const Item& b) { 54 | if (a.getValue() < b.getValue()) 55 | return Less; 56 | if (b.getValue() < a.getValue()) 57 | return Greater; 58 | return Equal; 59 | } 60 | 61 | 62 | inline std::ostream& operator<<(std::ostream& out, const Item& item) { 63 | item.print(out); 64 | return out; 65 | } 66 | 67 | inline bool Item::atEnd() const { 68 | return _current == _end; 69 | } 70 | 71 | inline Value Item::getValue() const { 72 | ASSERT(!atEnd()); 73 | return _value; 74 | } 75 | 76 | inline void Item::toNext() { 77 | ASSERT(!atEnd()); 78 | ++_current; 79 | if (!atEnd()) { 80 | ASSERT(_value >= *_current); 81 | _value = *_current; 82 | } 83 | } 84 | 85 | inline Item Item::getNext() const { 86 | ASSERT(!atEnd()); 87 | Item next(*this); 88 | next.toNext(); 89 | return next; 90 | } 91 | 92 | inline bool Item::operator==(const Item& item) { 93 | return getValue() == item.getValue(); 94 | } 95 | 96 | inline Item::Item(): _value(-1), _current(0), _end(0) {} 97 | 98 | inline Item::Item(Value value): _value(value), _current(0), _end(0) { 99 | ++_end; 100 | } 101 | 102 | inline Item::Item(const Value* begin, const Value* end): 103 | _value(begin != end ? *begin : 0), _current(begin), _end(end) {} 104 | 105 | inline size_t Item::getLength() const { 106 | return _end - _current; 107 | } 108 | 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /src/pqsim/Model.cpp: -------------------------------------------------------------------------------- 1 | #include "stdinc.h" 2 | #include "Model.h" 3 | -------------------------------------------------------------------------------- /src/pqsim/Model.h: -------------------------------------------------------------------------------- 1 | #ifndef MODEL_GUARD 2 | #define MODEL_GUARD 3 | 4 | #include "Item.h" 5 | #include 6 | 7 | namespace ModelHelper { 8 | class NullConfigurationBase {}; 9 | template struct OnSpans {}; 10 | template struct UseDecreaseTop {}; 11 | 12 | template 13 | inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<0>); 14 | template 15 | inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<1>); 16 | template 17 | inline Value pop(DS& ds, OnSpans<0>, UseDecreaseTop
); 18 | 19 | template 20 | inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<0>); 21 | template 22 | inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<1>); 23 | 24 | inline Value deduplicate 25 | (std::vector& pending, const Value& a, const Value& b); 26 | inline Item deduplicate 27 | (std::vector& pending, const Item& a, const Item& b); 28 | } 29 | 30 | template< 31 | bool OnSpans, 32 | bool Deduplicate, 33 | bool UseDecreaseTop, 34 | template class DataStructure, 35 | class ConfigurationBase = ModelHelper::NullConfigurationBase> 36 | class Model { 37 | public: 38 | Model(): _ds(Configuration()) {} 39 | template 40 | Model(const A& a): _ds(Configuration(a)) {} 41 | template 42 | Model(const A& a, const B& b): _ds(Configuration(a, b)) {} 43 | 44 | std::string getName() const { 45 | return _ds.getName() + 46 | (UseDecreaseTop ? " dectop" : "") + 47 | (OnSpans ? " on spans" : " on elements"); 48 | } 49 | 50 | void push(const Value* begin, const Value* end) { 51 | ModelHelper::push(_ds, begin, end, ModelHelper::OnSpans()); 52 | } 53 | 54 | Value pop() { 55 | return ModelHelper::pop(_ds, 56 | ModelHelper::OnSpans(), 57 | ModelHelper::UseDecreaseTop()); 58 | } 59 | 60 | bool empty() const {return _ds.empty();} 61 | void print(std::ostream& out) const {_ds.print(out);} 62 | 63 | size_t getComparisons() const { 64 | return _ds.getConfiguration().getComparisons(); 65 | } 66 | 67 | size_t getMemoryUse() const { 68 | return _ds.getMemoryUse(); 69 | } 70 | 71 | private: 72 | class Configuration : public ConfigurationBase { 73 | public: 74 | typedef typename ItemOrValue::Entry Entry; 75 | 76 | Configuration(): _comparisons(0) {} 77 | template 78 | Configuration(const A& a, const B& b): 79 | ConfigurationBase(a, b), _comparisons(0) {} 80 | 81 | typedef ::CompareResult CompareResult; 82 | CompareResult compare(const Entry& a, const Entry& b) const { 83 | ++_comparisons; 84 | return ::compare(a, b); 85 | } 86 | bool cmpLessThan(CompareResult r) const {return r == Less;} 87 | bool cmpEqual(CompareResult r) const { 88 | ASSERT(supportDeduplication); 89 | return r == Equal; 90 | } 91 | Entry deduplicate(const Entry& a, const Entry& b) const { 92 | ASSERT(supportDeduplication); 93 | return ModelHelper::deduplicate(_pending, a, b); 94 | } 95 | 96 | std::vector& getPending() {return _pending;} 97 | size_t getComparisons() const {return _comparisons;} 98 | 99 | static const bool supportDeduplication = Deduplicate; 100 | 101 | private: 102 | mutable size_t _comparisons; 103 | mutable std::vector _pending; 104 | }; 105 | 106 | DataStructure _ds; 107 | }; 108 | 109 | namespace ModelHelper { 110 | template 111 | inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<0>) { 112 | ds.push(begin, end); 113 | } 114 | template 115 | inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<1>) { 116 | ds.push(Item(begin, end)); 117 | } 118 | 119 | template 120 | inline Value pop(DS& ds, OnSpans<0>, UseDecreaseTop
) { 121 | Value topValue = ds.top(); 122 | do { 123 | ds.pop(); 124 | } while (!ds.empty() && ds.top() == topValue); 125 | return topValue; 126 | } 127 | 128 | template 129 | inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<0>) { 130 | ASSERT(DS::Configuration::supportDeduplication || 131 | ds.getConfiguration().getPending().empty()); 132 | Value topValue = ds.top().getValue(); 133 | do { 134 | Item top = ds.pop(); 135 | top.toNext(); 136 | if (!top.atEnd()) 137 | ds.push(top); 138 | 139 | if (DS::Configuration::supportDeduplication) { 140 | std::vector& pending = ds.getConfiguration().getPending(); 141 | while (!pending.empty()) { 142 | // this has to work even if push changes pending, which is 143 | // why the loop is done like this. 144 | Item item = pending.back(); 145 | pending.pop_back(); 146 | ds.push(item); 147 | } 148 | } else { 149 | ASSERT(ds.getConfiguration().getPending().empty()); 150 | } 151 | } while (!ds.empty() && ds.top().getValue() == topValue); 152 | ASSERT(DS::Configuration::supportDeduplication || 153 | ds.getConfiguration().getPending().empty()); 154 | return topValue; 155 | } 156 | 157 | template 158 | inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<1>) { 159 | ASSERT(DS::Configuration::supportDeduplication || 160 | ds.getConfiguration().getPending().empty()); 161 | Value topValue = ds.top().getValue(); 162 | do { 163 | Item top = ds.top(); 164 | top.toNext(); 165 | if (!top.atEnd()) 166 | ds.decreaseTop(top); 167 | else 168 | ds.pop(); 169 | 170 | ASSERT(DS::Configuration::supportDeduplication || 171 | ds.getConfiguration().getPending().empty()); 172 | if (DS::Configuration::supportDeduplication) { 173 | std::vector& pending = ds.getConfiguration().getPending(); 174 | while (!pending.empty()) { 175 | // this has to work even if push changes pending, which is 176 | // why the loop is done like this. 177 | Item item = pending.back(); 178 | pending.pop_back(); 179 | ds.push(item); 180 | } 181 | } 182 | } while (!ds.empty() && ds.top().getValue() == topValue); 183 | ASSERT(DS::Configuration::supportDeduplication || 184 | ds.getConfiguration().getPending().empty()); 185 | return topValue; 186 | } 187 | 188 | inline Value deduplicate 189 | (std::vector& pending, const Value& a, const Value& b) { 190 | return a; 191 | } 192 | inline Item deduplicate 193 | (std::vector& pending, const Item& a, const Item& b) { 194 | Item next = b; 195 | next.toNext(); 196 | if (!next.atEnd()) 197 | pending.push_back(next); 198 | return a; 199 | } 200 | } 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /src/pqsim/Simulator.cpp: -------------------------------------------------------------------------------- 1 | #include "stdinc.h" 2 | #include "Simulator.h" 3 | 4 | #include "mathic/ColumnPrinter.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace { 11 | std::string commafy(unsigned long l) { 12 | std::stringstream out; 13 | out << l; 14 | std::string str; 15 | for (size_t i = 0; i < out.str().size(); ++i) { 16 | str += out.str()[i]; 17 | if (i != out.str().size() - 1 && ((out.str().size() - i) % 3) == 1) 18 | str += ','; 19 | } 20 | return str; 21 | } 22 | 23 | struct SimBuilder { 24 | typedef Simulator::Event Event; 25 | SimBuilder(bool popDuplicates, 26 | std::vector& mem, 27 | std::vector& events): 28 | _popDuplicates(popDuplicates), 29 | _mem(mem), 30 | _events(events), 31 | _pushCount(0), 32 | _popCount(0), 33 | _liveCountSum(0), 34 | _pushSum(0), 35 | _duplicateCount(0) { 36 | _events.clear(); 37 | _mem.clear(); 38 | } 39 | 40 | size_t getLiveCount() const {return _queue.size();} 41 | size_t getPushCount() const {return _pushCount;} 42 | size_t getPushSum() const {return _pushSum;} 43 | size_t getPopCount() const {return _popCount;} 44 | size_t getAvgLiveCount() const { 45 | return _events.empty() ? 0 : _liveCountSum / _events.size(); 46 | } 47 | size_t getDupliateCount() const {return _duplicateCount;} 48 | 49 | // call nothing but addToPush and isInPush 50 | // after calling beginPush until you call endPush. 51 | void beginPush() { 52 | ASSERT(_push.empty()); 53 | _liveCountSum += getLiveCount(); 54 | _events.push_back(Event()); 55 | _events.back().begin = _mem.size(); 56 | } 57 | void addToPush(Value v) { 58 | if (isLive(v)) 59 | ++_duplicateCount; 60 | _push.insert(v); // for faster isInPush 61 | _mem.push_back(v); 62 | _queue.insert(v); 63 | } 64 | bool isInPush(Value v) { 65 | return _push.find(v) != _push.end(); 66 | } 67 | void endPush() { 68 | Event& e = _events.back(); 69 | e.size = _mem.size() - e.begin; 70 | std::vector::iterator begin = _mem.begin() + e.begin; 71 | std::sort(begin, begin + e.size, std::greater()); 72 | ++_pushCount; 73 | _pushSum += e.size; 74 | _push.clear(); 75 | } 76 | 77 | // todo: move clients to use begin...endpush 78 | template 79 | void push(It begin, It end) { 80 | beginPush(); 81 | for (It it = begin; it != end; ++it) 82 | addToPush(*it); 83 | endPush(); 84 | } 85 | 86 | Value pop() { 87 | _liveCountSum += getLiveCount(); 88 | ++_popCount; 89 | Value top = *_queue.rbegin(); 90 | do { 91 | std::multiset::iterator last = _queue.end(); 92 | --last; 93 | _queue.erase(last); 94 | } while (_popDuplicates && !_queue.empty() && *_queue.rbegin() == top); 95 | Event e; 96 | e.popValue = top; 97 | _events.push_back(e); 98 | return top; 99 | } 100 | 101 | bool noLive() const {return _queue.empty();} 102 | 103 | Value getRandomLive() const { 104 | ASSERT(!noLive()); 105 | const size_t randomIndex = rand() % _queue.size(); 106 | std::multiset::const_iterator it = _queue.begin(); 107 | std::advance(it, randomIndex); 108 | return *it; 109 | } 110 | 111 | bool isLive(Value v) const { 112 | return _queue.find(v) != _queue.end(); 113 | } 114 | 115 | private: 116 | bool _popDuplicates; 117 | std::multiset _queue; 118 | std::multiset _push; 119 | std::vector& _mem; 120 | std::vector& _events; 121 | size_t _pushCount; 122 | size_t _popCount; 123 | size_t _liveCountSum; 124 | size_t _pushSum; 125 | size_t _duplicateCount; 126 | }; 127 | 128 | std::string makeDescription(SimBuilder& sim, size_t repeats, 129 | std::string name) { 130 | std::ostringstream out; 131 | const size_t traffic = sim.getPushSum(); 132 | out << "*** Simulation \"" << name << "\"\n "; 133 | out << sim.getPushCount() << " spans\n "; 134 | out << (traffic / sim.getPushCount()) << " per span on average\n "; 135 | out << sim.getAvgLiveCount() << " elements in queue on average\n "; 136 | out << traffic << " entries popped in total.\n "; 137 | out << (sim.getDupliateCount() * 100 / traffic) << "% duplicates\n "; 138 | out << repeats << " repeats.\n"; 139 | return out.str(); 140 | } 141 | } 142 | 143 | void Simulator::dupSpans 144 | (size_t pushSumGoal, size_t avgSpan, size_t avgLiveGoal, 145 | size_t dupPercentage) { 146 | SimBuilder sim(true, _mem, _events); 147 | //size_t liveDeviation = 30; 148 | size_t spanDeviation = 10; 149 | ASSERT(avgSpan > 0); 150 | if (avgSpan <= spanDeviation) 151 | spanDeviation = avgSpan - 1; 152 | 153 | while (sim.getPushSum() < pushSumGoal || !sim.noLive()) { 154 | bool doPush = (sim.getAvgLiveCount() < avgLiveGoal); 155 | if (sim.getPushSum() == pushSumGoal) 156 | doPush = false; 157 | else if (sim.noLive()) 158 | doPush = true; 159 | 160 | if (doPush) { 161 | const size_t size = 162 | avgSpan - spanDeviation + rand() % (2 * spanDeviation); 163 | sim.beginPush(); 164 | for (size_t i = 0; i < size; ++i) { 165 | if (!sim.noLive() && 166 | static_cast(rand() % 100) <= dupPercentage) { 167 | Value v; 168 | size_t tries = 0; 169 | // if there are only fewer elements to duplicate than there 170 | // are elements in the push, then this will never succeed. 171 | // It will also take a long time to succeed even in some situations 172 | // where it is possible. So we only try it for so long. 173 | do { 174 | v = (tries < 20 ? sim.getRandomLive() : rand()); 175 | ++tries; 176 | } while (sim.isInPush(v)); 177 | sim.addToPush(v); 178 | } else { 179 | Value v; 180 | do { 181 | v = rand(); 182 | } while (sim.isInPush(v) || sim.isLive(v)); 183 | sim.addToPush(v); 184 | } 185 | } 186 | sim.endPush(); 187 | } else 188 | sim.pop(); 189 | } 190 | _description = makeDescription(sim, _repeats, "dup spans"); 191 | } 192 | 193 | void Simulator::orderSpans 194 | (size_t spanCount, size_t spanSize, size_t avgSize) { 195 | SimBuilder sim(true, _mem, _events); 196 | size_t insNum = (spanSize + spanCount * avgSize) * 3; 197 | size_t deviation = (spanSize) / 2; 198 | if (deviation == 0) 199 | deviation = 1; 200 | if (deviation > avgSize) 201 | deviation = avgSize - 1; 202 | 203 | while (sim.getLiveCount() > 0 || sim.getPushCount() < spanCount) { 204 | const size_t live = sim.getLiveCount(); 205 | const size_t minLive = avgSize - deviation; 206 | const size_t pushes = sim.getPushCount(); 207 | if (live == 0 || (pushes < spanCount && live < minLive)) { 208 | sim.beginPush(); 209 | for (size_t i = 0; i < spanSize; ++i) { 210 | Value v; 211 | do { 212 | v = insNum + rand() % (2*avgSize); 213 | } while (sim.isInPush(v)); 214 | --insNum; 215 | sim.addToPush(v); 216 | } 217 | sim.endPush(); 218 | } else 219 | sim.pop(); 220 | } 221 | 222 | _description = makeDescription(sim, _repeats, "ordered spans"); 223 | } 224 | 225 | void Simulator::randomSpans(size_t spanCount, size_t spanSize, size_t initialSize) { 226 | SimBuilder sim(false, _mem, _events); 227 | while (sim.getLiveCount() || sim.getPushCount() < spanCount) { 228 | bool doPop = rand() % (spanSize + 1) != 0; 229 | if (sim.getLiveCount() == 0) 230 | doPop = false; 231 | if (sim.getPushCount() == spanCount) 232 | doPop = true; 233 | 234 | if (doPop) 235 | sim.pop(); 236 | else { 237 | size_t size = (sim.getPushCount() == 0 ? initialSize : spanSize); 238 | sim.beginPush(); 239 | for (size_t i = 0; i < size; ++i) { 240 | Value v; 241 | do { 242 | v = rand(); 243 | } while (sim.isInPush(v)); 244 | sim.addToPush(v); 245 | } 246 | sim.endPush(); 247 | } 248 | } 249 | _description = makeDescription(sim, _repeats, "random spans"); 250 | } 251 | 252 | void Simulator::printEventSummary(std::ostream& out) const { 253 | out << _description << std::endl; 254 | } 255 | 256 | void Simulator::printEvents(std::ostream& out) const { 257 | out << "*** The " << _events.size() << " events are\n"; 258 | for (size_t i = 0; i < _events.size(); ++i) 259 | print(_events[i], out); 260 | } 261 | 262 | void Simulator::print(const Event& e, std::ostream& out) const { 263 | if (e.size == 0) 264 | out << "Pop " << e.popValue << '\n'; 265 | else { 266 | out << "Insert"; 267 | std::vector::const_iterator it = _mem.begin() + e.begin; 268 | std::vector::const_iterator end = it + e.size; 269 | for (; it != end; ++it) 270 | out << ' ' << *it; 271 | out << '\n'; 272 | } 273 | } 274 | 275 | void Simulator::printData(std::ostream& out) const { 276 | std::vector sorted(_data); 277 | sort(sorted.begin(), sorted.end()); 278 | out << "*** Simulation outcome ***" << std::endl; 279 | mic::ColumnPrinter pr; 280 | pr.addColumn(true); 281 | pr.addColumn(false, " ", "ms"); 282 | pr.addColumn(false, " ", "cmps"); 283 | pr.addColumn(false, " ", "kb"); 284 | for (std::vector::const_iterator it = sorted.begin(); 285 | it != sorted.end(); ++it) { 286 | pr[0] << it->name << '\n'; 287 | pr[1] << commafy(it->mseconds) << '\n'; 288 | pr[2] << commafy(it->comparisons) << '\n'; 289 | pr[3] << commafy(it->memoryUse / 1024) << '\n'; 290 | } 291 | pr.print(out); 292 | } 293 | 294 | void Simulator::setupEvents() { 295 | size_t activeSum = 0; 296 | std::priority_queue queue; 297 | typedef std::vector::iterator Iterator; 298 | Iterator end = _events.end(); 299 | for (Iterator it = _events.begin(); it != end; ++it) { 300 | Event& e = *it; 301 | activeSum += queue.size(); 302 | if (e.size == 0) { 303 | e.popValue = queue.top(); 304 | queue.pop(); 305 | } else { 306 | Value* begin = &(_mem[e.begin]); 307 | Value* end = begin + e.size; 308 | sort(begin, end, std::greater()); 309 | for (const Value* v = begin; v != end; ++v) 310 | queue.push(*v); 311 | } 312 | } 313 | _avgSize = activeSum / _events.size(); 314 | } 315 | 316 | void Simulator::SimData::print(std::ostream& out) { 317 | out << name 318 | << " " << commafy(mseconds) << " ms" 319 | << " " << commafy(comparisons) << " cmps" 320 | << " " << commafy(memoryUse / 1024) << " kb" 321 | << '\n'; 322 | } 323 | 324 | bool Simulator::SimData::operator<(const SimData& sd) const { 325 | return mseconds < sd.mseconds; 326 | } 327 | -------------------------------------------------------------------------------- /src/pqsim/Simulator.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMULATOR_GUARD 2 | #define SIMULATOR_GUARD 3 | 4 | #include "Item.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class Simulator { 14 | public: 15 | Simulator(size_t repeats): _repeats(repeats), _simType("none") {} 16 | 17 | void dupSpans(size_t pushSumGoal, size_t avgSpan, size_t avgLiveGoal, 18 | size_t dupPercentage); 19 | void orderSpans(size_t spanCount, size_t spanSize, size_t avgSize); 20 | void randomSpans(size_t spanCount, size_t spanSize, size_t initialSize); 21 | 22 | template 23 | void run(PQueue& pq, bool printData = true, bool printStates = false); 24 | 25 | void printEventSummary(std::ostream& out) const; 26 | void printEvents(std::ostream& out) const; 27 | void printData(std::ostream& out) const; 28 | 29 | struct Event { 30 | Event(): size(0) {} 31 | size_t begin; 32 | size_t size; // insert _mem( [begin, begin + size) ) if size > 0. 33 | Value popValue; // pop this value if size == 0 34 | }; 35 | 36 | private: 37 | struct SimData { 38 | std::string name; 39 | unsigned long comparisons; 40 | unsigned long mseconds; 41 | size_t memoryUse; 42 | bool operator<(const SimData& sd) const; 43 | void print(std::ostream& out); 44 | }; 45 | 46 | void setupEvents(); 47 | void print(const Event& e, std::ostream& out) const; 48 | 49 | std::vector _events; 50 | std::vector _data; 51 | std::vector _mem; 52 | size_t _spanCount; 53 | size_t _spanSize; 54 | size_t _avgSize; 55 | size_t _repeats; 56 | std::string _simType; 57 | std::string _description; 58 | }; 59 | 60 | template 61 | void Simulator::run(PQueue& pqueue, bool printData, bool printStates) { 62 | clock_t timeBegin = clock(); 63 | std::vector::const_iterator end = _events.end(); 64 | for (size_t turn = 0; turn < _repeats; ++turn) { 65 | typedef std::vector::const_iterator CIterator; 66 | CIterator end = _events.end(); 67 | for (CIterator it = _events.begin(); it != end; ++it) { 68 | const Event& e = *it; 69 | if (printStates) { 70 | std::cerr << "*** The next event is\n"; 71 | print(e, std::cerr); 72 | std::cerr << "*** The state of " << pqueue.getName() 73 | << " (" << pqueue.getComparisons() << " comparisons) is\n"; 74 | pqueue.print(std::cerr); 75 | std::cerr << '\n'; 76 | } 77 | if (e.size == 0) { 78 | Value item = pqueue.pop(); 79 | if (!(item == e.popValue)) { 80 | std::cerr << "ERROR: queue " << pqueue.getName() 81 | << " gave incorrect value " << item << std::endl; 82 | exit(1); 83 | } 84 | } else { 85 | const Value* begin = &_mem[e.begin]; 86 | pqueue.push(begin, begin + e.size); 87 | } 88 | } 89 | } 90 | clock_t timeEnd = clock(); 91 | 92 | SimData data; 93 | data.name = pqueue.getName(); 94 | data.memoryUse = pqueue.getMemoryUse(); 95 | data.comparisons = pqueue.getComparisons(); 96 | data.mseconds = (unsigned long) 97 | ((double(timeEnd) - timeBegin) * 1000) / CLOCKS_PER_SEC; 98 | _data.push_back(data); 99 | if (printData) 100 | data.print(std::cerr); 101 | } 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /src/pqsim/StlSetModel.h: -------------------------------------------------------------------------------- 1 | #ifndef STL_SET_MODEL_GUARD 2 | #define STL_SET_MODEL_GUARD 3 | 4 | #include "Model.h" 5 | #include "mathic/StlSet.h" 6 | 7 | template 8 | class StlSetModel : public Model {}; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/pqsim/TourTreeModel.h: -------------------------------------------------------------------------------- 1 | #ifndef TOUR_TREE_MODEL_GUARD 2 | #define TOUR_TREE_MODEL_GUARD 3 | 4 | #include "mathic/TourTree.h" 5 | #include "Model.h" 6 | 7 | template 8 | struct TourTreeModelBase { 9 | static const bool fastIndex = FastIndex; 10 | }; 11 | 12 | template 13 | class TourTreeModel : public Model< 14 | OnSpans, false, true, mathic::TourTree, TourTreeModelBase > {}; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/pqsim/pqMain.cpp: -------------------------------------------------------------------------------- 1 | #include "stdinc.h" 2 | 3 | #include "StlSetModel.h" 4 | #include "HeapModel.h" 5 | #include "GeobucketModel.h" 6 | #include "TourTreeModel.h" 7 | #include "Simulator.h" 8 | #include 9 | #include 10 | 11 | namespace { 12 | size_t toInt(const char* str) { 13 | std::istringstream in(str); 14 | size_t i; 15 | in >> i; 16 | return i; 17 | } 18 | } 19 | 20 | int main(int argc, const char** args) { 21 | srand(static_cast(time(0))); 22 | srand(0); 23 | if (argc < 4) { 24 | std::cerr << "usage: elements span-length target-avg-size\n"; 25 | return 0; 26 | } 27 | size_t elements = toInt(args[1]); 28 | size_t spanSize = toInt(args[2]); 29 | size_t avgOrInitialSize = toInt(args[3]); 30 | size_t dups = 30; 31 | if (argc >= 5) 32 | dups = toInt(args[4]); 33 | 34 | size_t repeats = 500; 35 | IF_DEBUG(repeats = 2;); 36 | 37 | std::cerr << "Generating simulation..." << std::endl; 38 | Simulator sim(repeats); 39 | //sim.orderSpans(elements / spanSize, spanSize, avgOrInitialSize); 40 | //sim.randomSpans(elements / spanSize, spanSize, avgOrInitialSize); 41 | sim.dupSpans(elements, spanSize, avgOrInitialSize, dups); 42 | sim.printEventSummary(std::cerr); 43 | //sim.printEvents(std::cerr); 44 | std::cerr << '\n' << std::endl; 45 | 46 | #ifdef DEBUG 47 | {TourTreeModel<0,0> x; sim.run(x);} 48 | {HeapModel<0,0,0> x; sim.run(x);} 49 | #else 50 | {TourTreeModel<1,0> x; sim.run(x);} 51 | {TourTreeModel<0,0> x; sim.run(x);} 52 | {GeobucketModel<0,0,0,0,0,0,0> x(4, 32); sim.run(x);} 53 | {GeobucketModel<0,0,0,0,0,0,0> x(2, 32); sim.run(x);} 54 | {GeobucketModel<0,0,0,1,0,0,0> x(4, 32); sim.run(x);} 55 | {StlSetModel<1> x; sim.run(x);} 56 | {StlSetModel<0> x; sim.run(x);} 57 | {HeapModel<0,0,0> x; sim.run(x);} 58 | {HeapModel<1,0,0> x; sim.run(x);} 59 | {HeapModel<0,1,0> x; sim.run(x);} 60 | {HeapModel<1,1,0> x; sim.run(x);} 61 | #endif 62 | 63 | sim.printData(std::cout); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /src/pqsim/pqMain.h: -------------------------------------------------------------------------------- 1 | #ifndef PQ_MAIN 2 | #define PQ_MAIN 3 | 4 | int main(int argc, const char** args); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/pqsim/stdinc.h: -------------------------------------------------------------------------------- 1 | #ifdef STDINC_GUARD 2 | #error stdinc.h included twice 3 | #endif 4 | #define STDINC_GUARD 5 | 6 | #ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++. 7 | #pragma warning (push, 1) // Reduce warning level for GMP headers. 8 | #endif 9 | 10 | #ifndef _MSC_VER 11 | #define NO_INLINE 12 | #endif 13 | 14 | #ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++. 15 | #define NO_INLINE __declspec(noinline) 16 | #pragma warning (pop) // Go back to previous warning level. 17 | #pragma warning (disable: 4996) // std::copy is flagged as dangerous. 18 | #pragma warning (disable: 4290) // VC++ ignores throw () specification. 19 | #pragma warning (disable: 4127) // Warns about using "while (true)". 20 | #pragma warning (disable: 4100) // Warns about unused parameters. 21 | #pragma warning (disable: 4800) // Warns on int to bool conversion. 22 | #pragma warning (disable: 4146) // Warns on unary minus on unsigned (bit trick) 23 | 24 | // This warning warns about using the this pointer in base member 25 | // initializer lists. This is a pretty good warning as that can 26 | // obviously easily go wrong, but it is pretty useful to do as well, 27 | // so the warning is turned off. 28 | #pragma warning (disable: 4355) 29 | 30 | #ifdef _DEBUG 31 | #define DEBUG 32 | #endif 33 | 34 | #endif 35 | 36 | #include 37 | #include 38 | 39 | #ifdef DEBUG 40 | #include // Useful for debugging. 41 | #define PRINT 42 | #include 43 | #define ASSERT(X) assert(X); 44 | #define IF_DEBUG(X) X 45 | #else 46 | #define ASSERT(X) 47 | #define IF_DEBUG(X) 48 | #endif 49 | -------------------------------------------------------------------------------- /src/test/BitTriangle.cpp: -------------------------------------------------------------------------------- 1 | #include "mathic/BitTriangle.h" 2 | #include 3 | 4 | TEST(BitTriangle, NoOp) { 5 | mathic::BitTriangle tri; 6 | }; 7 | 8 | TEST(BitTriangle, emptyAndColumnCount) { 9 | mathic::BitTriangle tri; 10 | ASSERT_TRUE(tri.empty()); 11 | ASSERT_EQ(0u, tri.columnCount()); 12 | 13 | tri.addColumn(); 14 | ASSERT_FALSE(tri.empty()); 15 | ASSERT_EQ(1u, tri.columnCount()); 16 | 17 | tri.addColumn(); 18 | ASSERT_FALSE(tri.empty()); 19 | ASSERT_EQ(2u, tri.columnCount()); 20 | } 21 | 22 | TEST(BitTriangle, getSetBit) { 23 | size_t const colCount = 20; // consider colCount columns 24 | size_t const modPattern = 11; 25 | mathic::BitTriangle tri; 26 | for (size_t col = 0; col < colCount; ++col) { 27 | tri.addColumn(); 28 | for (size_t row = 0; row < col; ++row) { 29 | ASSERT_FALSE(tri.bit(col, row)); 30 | ASSERT_FALSE(tri.bitUnordered(col, row)); 31 | ASSERT_FALSE(tri.bitUnordered(row, col)); 32 | 33 | tri.setBit(col, row, true); 34 | ASSERT_TRUE(tri.bit(col, row)); 35 | ASSERT_TRUE(tri.bitUnordered(col, row)); 36 | ASSERT_TRUE(tri.bitUnordered(row, col)); 37 | 38 | tri.setBitUnordered(col, row, false); 39 | ASSERT_FALSE(tri.bit(col, row)); 40 | ASSERT_FALSE(tri.bitUnordered(col, row)); 41 | ASSERT_FALSE(tri.bitUnordered(row, col)); 42 | 43 | tri.setBitUnordered(row, col, true); 44 | ASSERT_TRUE(tri.bit(col, row)); 45 | ASSERT_TRUE(tri.bitUnordered(col, row)); 46 | ASSERT_TRUE(tri.bitUnordered(row, col)); 47 | 48 | // set bits mod 11 since 3 is relatively prime to 2 49 | // so any mod 2^k pattern is avoided and 11>8 so we do 50 | // get bytes that are all ones. 51 | bool const value = ((row + col) % modPattern != 0); 52 | 53 | tri.setBit(col, row, value); 54 | ASSERT_EQ(value, tri.bit(col, row)); 55 | ASSERT_EQ(value, tri.bitUnordered(col, row)); 56 | ASSERT_EQ(value, tri.bitUnordered(row, col)); 57 | } 58 | } 59 | ASSERT_EQ(colCount, tri.columnCount()); 60 | 61 | // check that the pattern of bits is preserved 62 | for (size_t col = 0; col < colCount; ++col) { 63 | for (size_t row = 0; row < col; ++row) { 64 | bool const value = ((row + col) % 11 != 0); 65 | ASSERT_EQ(value, tri.bit(col, row)); 66 | ASSERT_EQ(value, tri.bitUnordered(col, row)); 67 | ASSERT_EQ(value, tri.bitUnordered(row, col)); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/DivFinder.cpp: -------------------------------------------------------------------------------- 1 | #include "divsim/stdinc.h" 2 | #include "mathic/KDTree.h" 3 | #include 4 | 5 | #include "mathic/DivList.h" 6 | #include "divsim/KDTreeModel.h" 7 | 8 | TEST(DivFinder, NoOp) { 9 | KDTreeModel<1,1,1,1,1> model(1, 1, 0, 0, 1.0, 1000); 10 | }; 11 | -------------------------------------------------------------------------------- /src/test/HashTable.cpp: -------------------------------------------------------------------------------- 1 | #include "mathic/HashTable.h" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace { 7 | class HashTableConf 8 | { 9 | public: 10 | typedef int Key; 11 | typedef int Value; 12 | 13 | size_t hash(Key k) {return k;} 14 | bool keysEqual(Key k1, Key k2) {return k1==k2;} 15 | }; 16 | 17 | typedef mathic::HashTable HashTab; 18 | } 19 | 20 | TEST(HashTable, NoOp) { 21 | HashTableConf C; 22 | HashTab H(C); 23 | 24 | H.insert(1,3); 25 | H.insert(14,7); 26 | H.insert(17,7); 27 | H.insert(14,4); 28 | 29 | HashTab::Handle *p = H.lookup(14); 30 | ASSERT_FALSE(p == NULL); 31 | ASSERT_EQ(p->key(),14); 32 | ASSERT_EQ(p->value(),7); 33 | }; 34 | 35 | namespace { 36 | class HashTableStringConf 37 | { 38 | public: 39 | typedef std::string Key; 40 | typedef size_t Value; 41 | typedef std::hash hashfcn; 42 | size_t hash(Key k) { 43 | hashfcn fcn; 44 | return fcn(k); 45 | } 46 | 47 | bool keysEqual(Key k1, Key k2) {return k1==k2;} 48 | }; 49 | 50 | typedef mathic::HashTable HashStringTab; 51 | } 52 | 53 | TEST(HashTable, StringKeys) { 54 | HashTableStringConf C; 55 | HashStringTab H(C); 56 | 57 | 58 | H.insert("hi there",3); 59 | H.insert("whooa",7); 60 | H.insert("whoah",7); 61 | H.insert("hi there",4); 62 | 63 | HashStringTab::Handle *p = H.lookup("hi there"); 64 | ASSERT_FALSE(p == NULL); 65 | ASSERT_EQ(p->key(),"hi there"); 66 | ASSERT_EQ(p->value(),3); 67 | 68 | p = H.lookup("hi There"); 69 | ASSERT_TRUE(p == NULL); 70 | }; 71 | 72 | -------------------------------------------------------------------------------- /src/test/gtestInclude.cpp: -------------------------------------------------------------------------------- 1 | // Includes a file from gtest that pulls in all of the implementation 2 | // of gtest. The gtest docs recommend building gtest individually for 3 | // each program rather than using an installed gtest and this is as 4 | // easy a way of doing it as any. Especially because it guarantees that 5 | // the compiler flags are the same, which is the whole point of the 6 | // recommendation to build gtest for each program. 7 | 8 | // the .. goes back from the include/ directory of gtest so we can 9 | // enter the src directory. 10 | #include <../src/gtest-all.cc> 11 | -------------------------------------------------------------------------------- /src/test/testMain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) { 4 | ::testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } 7 | --------------------------------------------------------------------------------