pax_global_header00006660000000000000000000000064131155522530014514gustar00rootroot0000000000000052 comment=2f4a411d79c4977934b242eceb38e56089ad3968 mathic-master/000077500000000000000000000000001311555225300136165ustar00rootroot00000000000000mathic-master/.gitignore000077500000000000000000000011051311555225300156060ustar00rootroot00000000000000# Compiled Object files *.slo *.lo *.o # Compiled Dynamic libraries *.so # Compiled Static libraries *.lai *.la *.a # Emacs backup files \#*\# *~ # Autotools generated files config.log config.status libtool .deps/ .dirstamp aclocal.m4 autom4te.cache/ Makefile.in Makefile configure .libs/ /build/autotools/compile /build/autotools/mathic.pc /build/autotools/test-driver # Visual studio generated files *.suo *.sdf *.opensdf *.vcxproj.user output/ # Configure build targets deb/ debnoass/ pro/ rel/ relass/ # test output /test-suite.log /unittest /unittest.log /unittest.trs mathic-master/Makefile.am000077500000000000000000000100331311555225300156520ustar00rootroot00000000000000# options passed to aclocal, which is a tool for making macroes visible to # autoconf. We use -I to tell aclocal where we put the local macros. ACLOCAL_AMFLAGS = -I build/autotools/m4 # Options passed to the C and C++ PreProcessor (CPP) and compiler AM_CPPFLAGS = -I${top_srcdir}/ libmathic_la_CPPFLAGS = $(DEPS_CFLAGS) # tell Libtool what the name of the library is. lib_LTLIBRARIES = libmathic.la # set the C++ compiler to include src/ AM_CXXFLAGS=-I$(top_srcdir)/src/ -std=gnu++0x # libraries that are needed by this library libmathic_la_LIBADD= $(DEPS_LIBS) # the sources that are built to make libmathic. libmathic_la_SOURCES = src/mathic/Timer.cpp \ src/mathic/ColumnPrinter.cpp src/mathic/DivMask.cpp \ src/mathic/Action.cpp src/mathic/BoolParameter.cpp \ src/mathic/CliParameter.cpp src/mathic/CliParser.cpp \ src/mathic/error.cpp src/mathic/HelpAction.cpp \ src/mathic/IntegerParameter.cpp src/mathic/StringParameter.cpp \ src/mathic/display.cpp src/mathic/BitTriangle.cpp src/mathic.cpp # The headers that libmathic installs. # Normally, automake strips the path from the files when installing them, # so src/mathic/x.h gets installed as just x.h. mathicA_include_HEADERS = src/mathic.h mathicA_includedir = $(includedir) # install remaining headers into subdirectory of the include dir mathicB_includedir = \ $(includedir)/mathic mathicB_include_HEADERS = src/mathic/Action.h src/mathic/Geobucket.h \ src/mathic/BinaryKDTree.h src/mathic/GeoFront.h \ src/mathic/BoolParameter.h src/mathic/Heap.h \ src/mathic/CliParameter.h src/mathic/HelpAction.h \ src/mathic/CliParser.h src/mathic/IntegerParameter.h \ src/mathic/ColumnPrinter.h src/mathic/KDEntryArray.h \ src/mathic/Comparer.h src/mathic/KDTree.h src/mathic/ComTree.h \ src/mathic/NameFactory.h src/mathic/display.h \ src/mathic/PackedKDTree.h src/mathic/DivFinder.h src/mathic/stdinc.h \ src/mathic/DivList.h src/mathic/StlSet.h src/mathic/DivMask.h \ src/mathic/StringParameter.h \ src/mathic/Timer.h src/mathic/error.h src/mathic/TourTree.h \ src/mathic/BitTriangle.h \ src/mathic/PairQueue.h \ src/mathic/HashTable.h pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = build/autotools/mathic.pc # When making a distribution file, Automake knows to include all files # that are necessary to build the project. EXTRA_DIST specifies files # to include beyond those used in the build process. EXTRA_DIST = autogen.sh # tell automake what programs are there that are not built automatically EXTRA_PROGRAMS = pqsim divsim # set up the divisor query simulation. Listing the headers in sources # ensure that those files are included in distributions. divsim_CPPFLAGS = $(DEPS_CFLAGS) divsim_SOURCES = src/divsim/divMain.cpp src/divsim/Simulation.cpp \ src/divsim/DivListModel.h src/divsim/KDTreeModel.h \ src/divsim/Simulation.h src/divsim/divMain.h src/divsim/Monomial.h \ src/divsim/stdinc.h divsim_LDADD = $(top_builddir)/libmathic.la -lmemtailor -lpthread # set up the priority queue simulation. Listing the headers in sources # ensure that those files are included in distributions. pqsim_CPPFLAGS = $(DEPS_CFLAGS) pqsim_SOURCES = src/pqsim/Item.cpp src/pqsim/Model.cpp \ src/pqsim/pqMain.cpp src/pqsim/Simulator.cpp \ src/pqsim/GeobucketModel.h src/pqsim/Model.h src/pqsim/stdinc.h \ src/pqsim/HeapModel.h src/pqsim/pqMain.h src/pqsim/StlSetModel.h \ src/pqsim/Item.h src/pqsim/Simulator.h src/pqsim/TourTreeModel.h pqsim_LDADD = $(top_builddir)/libmathic.la -lmemtailor -lpthread # set up tests to run on "make check" if with_gtest TESTS=unittest check_PROGRAMS=$(TESTS) unittest_CXXFLAGS = -I$(top_srcdir)/src/ -std=gnu++0x unittest_LDADD = $(top_builddir)/libmathic.la $(DEPS_LIBS) -lmemtailor -lpthread unittest_CPPFLAGS = $(DEPS_CFLAGS) test_LIBS= unittest_SOURCES=src/test/DivFinder.cpp src/test/gtestInclude.cpp \ src/test/testMain.cpp src/test/BitTriangle.cpp \ src/test/PairQueue.cpp \ src/test/HashTable.cpp else check: @echo @echo "Configure did not locate gtest, so unittests cannot be run." endif mathic-master/README.md000077500000000000000000000025761311555225300151120ustar00rootroot00000000000000mathic ====== Mathic is a C++ library of fast data structures designed for use in Groebner basis computation. This includes data structures for ordering S-pairs, performing divisor queries and ordering polynomial terms during polynomial reduction. With Mathic you get to use highly optimized code with little effort so that you can focus more of your time on whatever part of your Groebner basis implementation that you are interested in. The data structures use templates to allow you to use them with whatever representation of monomials/terms and coefficients that your code uses. In fact the only places where Mathic defines its own monomials/terms is in the test code and example code. Currently only dense representations of terms/monomials are suitable since Mathic will frequently ask "what is the exponent of variable number x in this term/monomial?". The paper "Practical Grobner Basis Computation" describes the data structures from a high level. It was presented at ISSAC 2012 and is available at http://arxiv.org/abs/1206.6940 The following copyright and license notice applies to all of the files in mathic. Copyright 2012 2013 Bjarke Hammersholt Roune (http://www.broune.com) and Michael Stillman Mathic is licensed for use under the terms of GNU Lesser General Public License version 2.0, and under any later version; the option is yours. See the files lgpl-*.txt in this directory. mathic-master/autogen.sh000077500000000000000000000001221311555225300156120ustar00rootroot00000000000000#!/bin/sh srcdir="`dirname '$0'`" autoreconf --verbose --install --force $srcdir mathic-master/build/000077500000000000000000000000001311555225300147155ustar00rootroot00000000000000mathic-master/build/autotools/000077500000000000000000000000001311555225300167465ustar00rootroot00000000000000mathic-master/build/autotools/.gitignore000077500000000000000000000001651311555225300207430ustar00rootroot00000000000000# Autotools generated files ar-lib config.guess config.sub depcomp install-sh ltmain.sh mathic-*.pc missing mathic-master/build/autotools/m4/000077500000000000000000000000001311555225300172665ustar00rootroot00000000000000mathic-master/build/autotools/m4/.gitignore000077500000000000000000000001411311555225300212550ustar00rootroot00000000000000# Autotools generated files libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 lt~obsolete.m4 mathic-master/build/autotools/mathic.pc.in000077500000000000000000000005151311555225300211500ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: mathic Description: C++ library of symbolic algebra data structures for use in Groebner basis computation. URL: https://github.com/broune/mathic Requires: memtailor Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lmathic Cflags: -I${includedir}/ mathic-master/build/vs12/000077500000000000000000000000001311555225300155105ustar00rootroot00000000000000mathic-master/build/vs12/mathic-lib/000077500000000000000000000000001311555225300175215ustar00rootroot00000000000000mathic-master/build/vs12/mathic-lib/mathic-lib.vcxproj000077500000000000000000000614661311555225300231670ustar00rootroot00000000000000 Debug-NoAssert Win32 Debug-NoAssert x64 Debug Win32 Debug x64 Release-Assert Win32 Release-Assert x64 Release Win32 Release x64 WarningAsError Win32 WarningAsError x64 {BEBD36F1-A124-4C01-8E67-3208D4472661} Win32Proj mathiclib StaticLibrary true v110 Unicode StaticLibrary true v110 Unicode StaticLibrary true v110 Unicode StaticLibrary true v110 Unicode StaticLibrary true v110 Unicode StaticLibrary true v110 Unicode StaticLibrary false v110 true Unicode StaticLibrary false v110 true Unicode StaticLibrary false v110 false Unicode StaticLibrary false v110 false Unicode true .lib $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ mathic true .lib $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ mathic true .lib $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ mathic true .lib $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ mathic true .lib $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ mathic true .lib $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ mathic false mathic .lib $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ false mathic .lib $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ false mathic .lib $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ false mathic .lib $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ NotUsing Level3 Disabled MEMTAILOR_DEBUG;MATHIC_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;MATHICLIB_EXPORTS;%(PreprocessorDefinitions) C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false false Windows true NotUsing Level3 Disabled MEMTAILOR_DEBUG;MATHIC_DEBUG;WIN64;_DEBUG;_WINDOWS;_USRDLL;MATHICLIB_EXPORTS;%(PreprocessorDefinitions) C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false false Windows true NotUsing Level3 Disabled MEMTAILOR_DEBUG;MATHIC_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;MATHICLIB_EXPORTS;%(PreprocessorDefinitions) C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false true false Windows true NotUsing Level3 Disabled MEMTAILOR_DEBUG;MATHIC_DEBUG;WIN64;_DEBUG;_WINDOWS;_USRDLL;MATHICLIB_EXPORTS;%(PreprocessorDefinitions) C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false true false Windows true NotUsing Level3 Disabled WIN32;NDEBUG;_WINDOWS;_USRDLL;MATHICLIB_EXPORTS;%(PreprocessorDefinitions) C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false false Windows true NotUsing Level3 Disabled WIN64;NDEBUG;_WINDOWS;_USRDLL;MATHICLIB_EXPORTS;%(PreprocessorDefinitions) C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false false Windows true Level3 NotUsing MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;MATHICLIB_EXPORTS;%(PreprocessorDefinitions) C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false Windows true true true Level3 NotUsing MaxSpeed true true WIN64;NDEBUG;_WINDOWS;_USRDLL;MATHICLIB_EXPORTS;%(PreprocessorDefinitions) C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false Windows true true true Level3 NotUsing MaxSpeed true true MEMTAILOR_DEBUG;MATHIC_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;MATHICLIB_EXPORTS;%(PreprocessorDefinitions) C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true MultiThreadedDebugDLL false Windows true true true Level3 NotUsing MaxSpeed true true MEMTAILOR_DEBUG;MATHIC_DEBUG;WIN64;_DEBUG;_WINDOWS;_USRDLL;MATHICLIB_EXPORTS;%(PreprocessorDefinitions) C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true MultiThreadedDebugDLL false Windows true true true mathic-master/build/vs12/mathic-lib/mathic-lib.vcxproj.filters000077500000000000000000000133131311555225300246220ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files mathic-master/build/vs12/mathic-test/000077500000000000000000000000001311555225300177325ustar00rootroot00000000000000mathic-master/build/vs12/mathic-test/mathic-test.vcxproj000077500000000000000000000601321311555225300235760ustar00rootroot00000000000000 Debug-NoAssert Win32 Debug-NoAssert x64 Debug Win32 Debug x64 Release-Assert Win32 Release-Assert x64 Release Win32 Release x64 WarningAsError Win32 WarningAsError x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF} Win32Proj mathictest Application true v110 Unicode Application true v110 Unicode Application true v110 Unicode Application true v110 Unicode Application true v110 Unicode Application true v110 Unicode Application false v110 true Unicode Application false v110 true Unicode Application false v110 false Unicode Application false v110 false Unicode true $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ true $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ true $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ true $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ true $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ true $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ false $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ false $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ false $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ false $(SolutionDir)\output\$(Platform)\$(Configuration)\ $(SolutionDir)\output\$(Platform)\$(Configuration)\intermediate\$(MSBuildProjectName)\ NotUsing Level3 Disabled MEMTAILOR_DEBUG;MATHIC_DEBUG;_VARIADIC_MAX=10;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) C:\projs\mathic\gtest\include;C:\projs\mathic\gtest;C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false Console true $(SolutionDir)\output\$(Platform)\$(Configuration)\ %(AdditionalDependencies) NotUsing Level3 Disabled MEMTAILOR_DEBUG;MATHIC_DEBUG;_VARIADIC_MAX=10;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) C:\projs\mathic\gtest\include;C:\projs\mathic\gtest;C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false Console true $(SolutionDir)\output\$(Platform)\$(Configuration)\ %(AdditionalDependencies) NotUsing Level3 Disabled MEMTAILOR_DEBUG;MATHIC_DEBUG;_VARIADIC_MAX=10;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) C:\projs\mathic\gtest\include;C:\projs\mathic\gtest;C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false Console true $(SolutionDir)\output\$(Platform)\$(Configuration)\ %(AdditionalDependencies) NotUsing Level3 Disabled MEMTAILOR_DEBUG;MATHIC_DEBUG;_VARIADIC_MAX=10;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) C:\projs\mathic\gtest\include;C:\projs\mathic\gtest;C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false Console true $(SolutionDir)\output\$(Platform)\$(Configuration)\ %(AdditionalDependencies) NotUsing Level3 Disabled _VARIADIC_MAX=10;WIN32;_CONSOLE;%(PreprocessorDefinitions) C:\projs\mathic\gtest\include;C:\projs\mathic\gtest;C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false Console true $(SolutionDir)\output\$(Platform)\$(Configuration)\ %(AdditionalDependencies) NotUsing Level3 Disabled _VARIADIC_MAX=10;WIN64;_CONSOLE;%(PreprocessorDefinitions) C:\projs\mathic\gtest\include;C:\projs\mathic\gtest;C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true false Console true $(SolutionDir)\output\$(Platform)\$(Configuration)\ %(AdditionalDependencies) Level3 NotUsing MaxSpeed true true MEMTAILOR_DEBUG;MATHIC_DEBUG;_VARIADIC_MAX=10;WIN32;_CONSOLE;%(PreprocessorDefinitions) C:\projs\mathic\gtest\include;C:\projs\mathic\gtest;C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true Console true true true $(SolutionDir)\output\$(Platform)\$(Configuration)\ %(AdditionalDependencies) Level3 NotUsing MaxSpeed true true MEMTAILOR_DEBUG;MATHIC_DEBUG;_VARIADIC_MAX=10;WIN64;_CONSOLE;%(PreprocessorDefinitions) C:\projs\mathic\gtest\include;C:\projs\mathic\gtest;C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true Console true true true $(SolutionDir)\output\$(Platform)\$(Configuration)\ %(AdditionalDependencies) Level3 NotUsing MaxSpeed true true MEMTAILOR_DEBUG;MATHIC_DEBUG;_VARIADIC_MAX=10;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) C:\projs\mathic\gtest\include;C:\projs\mathic\gtest;C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true MultiThreadedDebugDLL Console true true true $(SolutionDir)\output\$(Platform)\$(Configuration)\ %(AdditionalDependencies) Level3 NotUsing MaxSpeed true true MEMTAILOR_DEBUG;MATHIC_DEBUG;_VARIADIC_MAX=10;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) C:\projs\mathic\gtest\include;C:\projs\mathic\gtest;C:\projs\mathic\memtailor\src;C:\projs\mathic\mathic\src;%(AdditionalIncludeDirectories) true MultiThreadedDebugDLL Console true true true $(SolutionDir)\output\$(Platform)\$(Configuration)\ %(AdditionalDependencies) {534c44f8-ba0a-4af0-95f1-260ca8ef3551} {bebd36f1-a124-4c01-8e67-3208d4472661} mathic-master/build/vs12/mathic-test/mathic-test.vcxproj.filters000077500000000000000000000030161311555225300252430ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files Source Files Source Files Source Files Source Files Source Files mathic-master/build/vs12/mathic.sln000077500000000000000000000150371311555225300175040ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathic-lib", "mathic-lib\mathic-lib.vcxproj", "{BEBD36F1-A124-4C01-8E67-3208D4472661}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathic-test", "mathic-test\mathic-test.vcxproj", "{9B09A868-B169-43E8-AFF9-D2F12657ABCF}" ProjectSection(ProjectDependencies) = postProject {BEBD36F1-A124-4C01-8E67-3208D4472661} = {BEBD36F1-A124-4C01-8E67-3208D4472661} {534C44F8-BA0A-4AF0-95F1-260CA8EF3551} = {534C44F8-BA0A-4AF0-95F1-260CA8EF3551} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memtailor-lib", "..\..\..\memtailor\build\vs12\memtailor-lib\memtailor-lib.vcxproj", "{534C44F8-BA0A-4AF0-95F1-260CA8EF3551}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Debug-NoAssert|Win32 = Debug-NoAssert|Win32 Debug-NoAssert|x64 = Debug-NoAssert|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 Release-Assert|Win32 = Release-Assert|Win32 Release-Assert|x64 = Release-Assert|x64 WarningAsError|Win32 = WarningAsError|Win32 WarningAsError|x64 = WarningAsError|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug|Win32.ActiveCfg = Debug|Win32 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug|Win32.Build.0 = Debug|Win32 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug|x64.ActiveCfg = Debug|x64 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug|x64.Build.0 = Debug|x64 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug-NoAssert|Win32.ActiveCfg = Debug-NoAssert|Win32 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug-NoAssert|Win32.Build.0 = Debug-NoAssert|Win32 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug-NoAssert|x64.ActiveCfg = Debug-NoAssert|x64 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Debug-NoAssert|x64.Build.0 = Debug-NoAssert|x64 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release|Win32.ActiveCfg = Release|Win32 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release|Win32.Build.0 = Release|Win32 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release|x64.ActiveCfg = Release|x64 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release|x64.Build.0 = Release|x64 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release-Assert|Win32.ActiveCfg = Release-Assert|Win32 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release-Assert|Win32.Build.0 = Release-Assert|Win32 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release-Assert|x64.ActiveCfg = Release-Assert|x64 {BEBD36F1-A124-4C01-8E67-3208D4472661}.Release-Assert|x64.Build.0 = Release-Assert|x64 {BEBD36F1-A124-4C01-8E67-3208D4472661}.WarningAsError|Win32.ActiveCfg = WarningAsError|Win32 {BEBD36F1-A124-4C01-8E67-3208D4472661}.WarningAsError|Win32.Build.0 = WarningAsError|Win32 {BEBD36F1-A124-4C01-8E67-3208D4472661}.WarningAsError|x64.ActiveCfg = WarningAsError|x64 {BEBD36F1-A124-4C01-8E67-3208D4472661}.WarningAsError|x64.Build.0 = WarningAsError|x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug|Win32.ActiveCfg = Debug|Win32 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug|Win32.Build.0 = Debug|Win32 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug|x64.ActiveCfg = Debug|x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug|x64.Build.0 = Debug|x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug-NoAssert|Win32.ActiveCfg = Debug-NoAssert|Win32 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug-NoAssert|Win32.Build.0 = Debug-NoAssert|Win32 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug-NoAssert|x64.ActiveCfg = Debug-NoAssert|x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Debug-NoAssert|x64.Build.0 = Debug-NoAssert|x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release|Win32.ActiveCfg = Release|Win32 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release|Win32.Build.0 = Release|Win32 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release|x64.ActiveCfg = Release|x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release|x64.Build.0 = Release|x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release-Assert|Win32.ActiveCfg = Release-Assert|Win32 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release-Assert|Win32.Build.0 = Release-Assert|Win32 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release-Assert|x64.ActiveCfg = Release-Assert|x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.Release-Assert|x64.Build.0 = Release-Assert|x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.WarningAsError|Win32.ActiveCfg = WarningAsError|Win32 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.WarningAsError|Win32.Build.0 = WarningAsError|Win32 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.WarningAsError|x64.ActiveCfg = WarningAsError|x64 {9B09A868-B169-43E8-AFF9-D2F12657ABCF}.WarningAsError|x64.Build.0 = WarningAsError|x64 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug|Win32.ActiveCfg = Debug|Win32 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug|Win32.Build.0 = Debug|Win32 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug|x64.ActiveCfg = Debug|x64 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug|x64.Build.0 = Debug|x64 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug-NoAssert|Win32.ActiveCfg = Debug-NoAssert|Win32 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug-NoAssert|Win32.Build.0 = Debug-NoAssert|Win32 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug-NoAssert|x64.ActiveCfg = Debug-NoAssert|x64 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Debug-NoAssert|x64.Build.0 = Debug-NoAssert|x64 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release|Win32.ActiveCfg = Release|Win32 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release|Win32.Build.0 = Release|Win32 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release|x64.ActiveCfg = Release|x64 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release|x64.Build.0 = Release|x64 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release-Assert|Win32.ActiveCfg = Release-Assert|Win32 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release-Assert|Win32.Build.0 = Release-Assert|Win32 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release-Assert|x64.ActiveCfg = Release-Assert|x64 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.Release-Assert|x64.Build.0 = Release-Assert|x64 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.WarningAsError|Win32.ActiveCfg = WarningAsError|Win32 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.WarningAsError|Win32.Build.0 = WarningAsError|Win32 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.WarningAsError|x64.ActiveCfg = WarningAsError|x64 {534C44F8-BA0A-4AF0-95F1-260CA8EF3551}.WarningAsError|x64.Build.0 = WarningAsError|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal mathic-master/configure.ac000077500000000000000000000122261311555225300161120ustar00rootroot00000000000000dnl AC_INIT sets up autoconf and must be first macro. AC_INIT([mathic], [1.0]) # package, version, bug-report-email # set up information about directories AC_CONFIG_MACRO_DIR([build/autotools/m4]) # directory of extra autoconf macroes AC_CONFIG_AUX_DIR([build/autotools]) # directory for auxiliary build tools (install-sh etc) # check that source directory is correct dnl if autoconf is told the source code is in a directory that does not dnl contain this file then it knows that the directory is wrong. AC_CONFIG_SRCDIR([src/mathic.h]) # Check that memtailor is installed and locate it # PKG_CHECK_MODULES([MEMTAILOR], [memtailor]) AM_PROG_AR dnl ----- The gtest dependency AC_ARG_WITH([gtest], AS_HELP_STRING( [--with-gtest], [use gtest, which is required for running the unit tests with make check. The value download, which is the default, downloads gtest if a gtest source directory cannot be found. Per the recommendation of the gtest documentation, gtest is compiled with the tests, so an installed gtest is not usable - you need the gtest source. GTEST_PATH indicates where to look for gtest and it is also where gtest will be downloaded to if not found. The default path is srcdir/libs so that gtest needs to be at srcdir/libs/gtest/ where srcdir is the base of the directory being configured from.] )) AC_MSG_CHECKING([for gtest]) AS_IF([test "$GTEST_PATH" = ""], [GTEST_PATH="$srcdir/libs"]) AS_IF([test "$GTEST_VERSION" = ""], [GTEST_VERSION="1.6.0"]) AS_IF([test "$with_gtest" = ""], [with_gtest="download"]) AS_IF([test "$with_gtest" = "download"], [with_gtest="yes"; AC_CHECK_FILE([$GTEST_PATH/src/gtest-all.cc], [], [ mkdir -p "$GTEST_PATH"; ( cd $GTEST_PATH; rm -rf gtest-$GTEST_VERSION.zip wget http://googletest.googlecode.com/files/gtest-$GTEST_VERSION.zip; unzip gtest-$GTEST_VERSION.zip; rm gtest-$GTEST_VERSION.zip rm -rf gtest/ mv gtest-$GTEST_VERSION/ gtest/ ); if test ! -e "$GTEST_PATH/src/gtest-all.cc"; then AC_MSG_WARN([Failed to download or extract gtest.]); with_gtest="no"; else with_gtest="yes"; fi ])], [test "$with_gtest" = "yes"], [ AC_CHECK_FILE([$GTEST_PATH/src/gtest-all.cc], [], [ AC_MSG_ERROR([could not find gtest source at path $GTEST_PATH.]) ]) ], [test "$with_gtest" = "no"], [], [AC_MSG_ERROR([invalid value $with_gtest for with_gtest.])] ) AS_IF([test "$with_gtest" = "yes"], [CPPFLAGS="-I$GTEST_PATH/include -I$GTEST_PATH $CPPFLAGS"]); AM_CONDITIONAL(with_gtest, test "$with_gtest" = "yes") DEPS_CFLAGS="$MEMTAILOR_CFLAGS $GTEST_CFLAGS" DEPS_LIBS="$MEMTAILOR_LIBS $GTEST_LIBS" AC_SUBST(DEPS_CFLAGS) AC_SUBST(DEPS_LIBS) # Enable optional maintainer mode (off by default) dnl AM_MAINTAINER_MODE turns off automatic reconstruction of the build dnl files if the source build files have changed. A developer will want dnl those automatic reconstructions to happen so that changes to the dnl build system are actually carried out. However, a user might not dnl have the tools required to reconfigure and the need for dnl reconstruction might be spurious if the last-modified date is set dnl incorrectly on the build files. dnl dnl Passing the option [enable] to AM_MAINTAINER_MODE makes the dnl non-reconstruction feature available, but only when turned on by dnl passing the option –disable-maintainer-mode. This option is dnl apparently useful to some package distributors. AM_MAINTAINER_MODE([enable]) # Set up Automake dnl foreign: do not create the GNU-specific file COPYING and do not complain dnl that GNU-specific files like NEWS, README, AUTHORS and ChangeLog are dnl missing. dnl -Wall: set Automake to emit all warnings it can. Is NOT RELATED to setting dnl warnings for other tools. For example, it wil not make the compiler dnl get a -Wall option. dnl subdir-objects: Put object files in a directory structure based on dnl the directory structure of the source files. This way, two source dnl files with the same name in different directories do not conflict. AM_INIT_AUTOMAKE([foreign subdir-objects -Wall]) # if --enable-silent-rules is passed to ./configure or if V=0 is passed # to make, then the compilation output will be much less verbose making # it possible to spot warnings and errors as they go by. AM_SILENT_RULES() # Set up the $(LN_S) macro, which creates symbolic links AC_PROG_LN_S # set output variable INSTALL to the name of a BSD-compatible install program. # Requires install-sh to be present as a fallback, even on systems where # the fallback is not used. AC_PROG_INSTALL # Locate the C++ compiler. AC_PROG_CXX # Set up LibTool LT_INIT([disable-shared]) dnl Set the version for the library -- this concerns compatibility of the dnl source and binary interface of the library and is not the same as the dnl version of the project. AC_SUBST([MATHIC_SO_VERSION], [0:0:0]) dnl Set up AC_OUTPUT to create each file by copying an input file dnl while substituting the output variable values. AC_CONFIG_FILES([Makefile build/autotools/mathic.pc:build/autotools/mathic.pc.in]) dnl Macro that is required to be at the end of any Autoconf script. dnl Creates config.status and launches it. AC_OUTPUT mathic-master/fixspace000077500000000000000000000042771311555225300153600ustar00rootroot00000000000000#!/bin/bash # Does the following operations on the files passed as arguments: # - Remove trailing space from lines # - Remove trailing blank lines # - Remove/convert DOS-style line breaks # - Expand tabs to spaces with a tabspace of 8 # I once had an error where the conversion had an error (the computer # didn't have dos2unix), resulting in the converted files being empty. # The result was that every file got replaced by an empty file! That # was not so nice, so this script stops operation as soon as any error # occurs, and it also checks that only space has been changed before # it overwrites the original file with a space-fixed version. for f in $*; do echo $f; tr -d '\r' < $f > __spaceTmp0; if [ $? != 0 ]; then echo "There was an error removing DOS-style line breaks."; exit 1; fi; expand -4 < __spaceTmp0 > __spaceTmp1; if [ $? != 0 ]; then echo "There was an error expanding tabs."; exit 1; fi; sed 's/[[:blank:]]*$//g' < __spaceTmp1 > __spaceTmp2; if [ $? != 0 ]; then echo "There was an error eliminating trailing space from lines."; exit 1; fi; # Make completely sure that we only changed the spaces diff -EbwB -q $f __spaceTmp2; if [ $? != 0 ]; then echo "There was an error. Conversion not confirmed correct."; exit 1; fi; sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' < __spaceTmp2 > __spaceTmp3; if [ $? != 0 ]; then echo "There was an error eliminating trailing blank lines."; exit 1; fi; # We have to do diff twice, because diff will not ignore trailing # lines that consist only of spaces. It will ignore changes to space and removal of # completely empty lines, so if we do it twice we get the right thing. # Make completely sure that we only changed the spaces diff -EbwB -q __spaceTmp2 __spaceTmp3; if [ $? != 0 ]; then echo "There was an error. Conversion not confirmed correct."; exit 1; fi; diff -q $f __spaceTmp3 1>/dev/null; if [ $? != 0 ]; then mv -f __spaceTmp3 $f; if [ $? != 0 ]; then echo "There was an error moving fixed file into place."; exit 1; fi; echo "Fixed space issue for $f." fi rm -f __spaceTmp0 __spaceTmp1 __spaceTmp2 __spaceTmp3; if [ $? != 0 ]; then echo "There was an error removing temporary files."; exit 1; fi; done; mathic-master/include/000077500000000000000000000000001311555225300152415ustar00rootroot00000000000000mathic-master/include/mathic/000077500000000000000000000000001311555225300165065ustar00rootroot00000000000000mathic-master/include/mathic/mathic.cpp000077500000000000000000000011351311555225300204620ustar00rootroot00000000000000// This implementation file includes all the implementation files needed // to get MemTailor working. #include "mathic.h" #include "../../src/Timer.cpp" #include "../../src/ColumnPrinter.cpp" #include "../../src/DivMask.cpp" #include "../../src/Action.cpp" #include "../../src/BoolParameter.cpp" #include "../../src/CliParameter.cpp" #include "../../src/CliParser.cpp" #include "../../src/NameFactory.cpp" #include "../../src/error.cpp" #include "../../src/HelpAction.cpp" #include "../../src/IntegerParameter.cpp" #include "../../src/StringParameter.cpp" #include "../../src/display.cpp" mathic-master/include/mathic/mathic.h000077500000000000000000000013511311555225300201270ustar00rootroot00000000000000// Include this file to pull in all external MemTailor files // utilities #include "../../src/Timer.h" #include "../../src/ColumnPrinter.h" #include "../../src/error.h" // divisor query data structures #include "../../src/DivList.h" #include "../../src/KDTree.h" // priority queue data structures #include "../../src/TourTree.h" #include "../../src/StlSet.h" #include "../../src/Heap.h" #include "../../src/Geobucket.h" // CLI package #include "../../src/Action.h" #include "../../src/BoolParameter.h" #include "../../src/CliParameter.h" #include "../../src/CliParser.h" #include "../../src/HelpAction.h" #include "../../src/IntegerParameter.h" #include "../../src/StringParameter.h" #include "../../src/display.h" mathic-master/lgpl-2.0.txt000066400000000000000000000614471311555225300156260ustar00rootroot00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! mathic-master/lgpl-2.1.txt000066400000000000000000000636421311555225300156260ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! mathic-master/lgpl-3.0.txt000066400000000000000000000167431311555225300156260ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. mathic-master/libs/000077500000000000000000000000001311555225300145475ustar00rootroot00000000000000mathic-master/libs/.gitignore000077500000000000000000000000071311555225300165370ustar00rootroot00000000000000gtest/ mathic-master/replace000077500000000000000000000003321311555225300151550ustar00rootroot00000000000000#!/bin/bash echo "Running script \"sed s/$1/$2/\"" for i in 1 2 3; do /usr/bin/sleep 1; echo -n .; done for f in `ls src/*.cpp src/*.h`; do echo "Processing $f"; sed "s/$1/$2/" < $f > $f.tmp mv $f.tmp $f done mathic-master/src/000077500000000000000000000000001311555225300144055ustar00rootroot00000000000000mathic-master/src/divsim/000077500000000000000000000000001311555225300157005ustar00rootroot00000000000000mathic-master/src/divsim/DivListModel.h000077500000000000000000000125031311555225300204140ustar00rootroot00000000000000#ifndef DIV_ARRAY_MODEL_GUARD #define DIV_ARRAY_MODEL_GUARD #include "Monomial.h" #include "mathic/DivList.h" #include #include /** Helper class for DivListModel. */ template class DivListModelConfiguration; template class DivListModelConfiguration { public: typedef int Exponent; typedef ::Monomial Monomial; typedef Monomial Entry; DivListModelConfiguration (size_t varCount, bool sortOnInsert, double rebuildRatio, size_t minRebuild): _varCount(varCount), _sortOnInsert(sortOnInsert), _useAutomaticRebuild((rebuildRatio > 0.0 || minRebuild > 0) && UDM), _rebuildRatio(rebuildRatio), _minRebuild(minRebuild), _expQueryCount(0) {} static const bool UseLinkedList = ULL; static const bool UseDivMask = UDM; bool getDoAutomaticRebuilds() const {return _useAutomaticRebuild;} double getRebuildRatio() const {return _rebuildRatio;} size_t getRebuildMin() const {return _minRebuild;} bool getSortOnInsert() const {return _sortOnInsert;} size_t getVarCount() const {return _varCount;} Exponent getExponent(const Monomial& monomial, size_t var) const { ++_expQueryCount; ASSERT(var < monomial.size()); return monomial[var]; } bool divides(const Monomial& a, const Monomial& b) const { for (size_t var = 0; var < getVarCount(); ++var) if (getExponent(b, var) < getExponent(a, var)) return false; return true; } bool isLessThan(const Monomial& a, const Monomial& b) const { for (size_t var = 0; var < getVarCount(); ++var) { if (getExponent(a, var) < getExponent(b, var)) return true; if (getExponent(b, var) < getExponent(a, var)) return false; } return false; } unsigned long long getExpQueryCount() const {return _expQueryCount;} private: const size_t _varCount; const bool _sortOnInsert; const bool _useAutomaticRebuild; const double _rebuildRatio; const size_t _minRebuild; mutable unsigned long long _expQueryCount; }; template class DivListModel; /** An instantiation of the capabilities of DivList. */ template class DivListModel { private: typedef DivListModelConfiguration C; typedef mathic::DivList Finder; public: typedef typename Finder::iterator iterator; typedef typename Finder::const_iterator const_iterator; typedef typename Finder::Monomial Monomial; typedef typename Finder::Entry Entry; DivListModel(size_t varCount, bool minimizeOnInsert, bool moveDivisorToFront, bool sortOnInsert, double rebuildRatio, size_t minRebuild): _finder(C(varCount, sortOnInsert, rebuildRatio, minRebuild)), _minimizeOnInsert(minimizeOnInsert), _moveDivisorToFront(moveDivisorToFront) { ASSERT(!sortOnInsert || !moveDivisorToFront); } void insert(const Entry& entry); template void insert(const Entry& entry, MultipleOutput& removed); Entry* findDivisor(const Monomial& monomial) { iterator it = _finder.findDivisorIterator(monomial); if (_moveDivisorToFront && it != _finder.end()) { _finder.moveToFront(it); it = _finder.begin(); } return it == end() ? 0 : &*it; } const Entry* findDivisor(const Monomial& monomial) const { return const_cast&>(*this).findDivisor(monomial); } template void findAllDivisors(const Monomial& monomial, DO& out) { _finder.findAllDivisors(monomial, out); } template void findAllDivisors(const Monomial& monomial, DO& out) const { _finder.findAllDivisors(monomial, out); } template void forAll(EO& out) { _finder.forAll(out); } template void forAll(EO& out) const { _finder.forAll(out); } std::string getName() const; iterator begin() {return _finder.begin();} const_iterator begin() const {return _finder.begin();} iterator end() {return _finder.end();} const_iterator end() const {return _finder.end();} size_t size() const {return _finder.size();} unsigned long long getExpQueryCount() const { return _finder.getConfiguration().getExpQueryCount(); } private: Finder _finder; const bool _minimizeOnInsert; const bool _moveDivisorToFront; }; template inline void DivListModel::insert(const Entry& entry) { if (!_minimizeOnInsert) { _finder.insert(entry); return; } if (findDivisor(entry) != 0) return; bool hasMultiples = _finder.removeMultiples(entry); _finder.insert(entry); if (_moveDivisorToFront && hasMultiples) { iterator it = _finder.end(); _finder.moveToFront(--it); } } template template inline void DivListModel::insert(const Entry& entry, MO& out) { if (!_minimizeOnInsert) { _finder.insert(entry); return; } if (findDivisor(entry) != 0) return; bool hasMultiples = _finder.removeMultiples(entry, out); _finder.insert(entry); if (_moveDivisorToFront && hasMultiples) { iterator it = _finder.end(); _finder.moveToFront(--it); } } template inline std::string DivListModel::getName() const { return _finder.getName() + (_minimizeOnInsert ? " remin" : " nomin") + (_moveDivisorToFront ? " toFront" : ""); } #endif mathic-master/src/divsim/KDTreeModel.h000077500000000000000000000122121311555225300201510ustar00rootroot00000000000000#ifndef K_D_TREE_MODEL_GUARD #define K_D_TREE_MODEL_GUARD #include "Monomial.h" #include "mathic/KDTree.h" #include #include template< bool UseDivMask, bool UseTreeDivMask, bool PackedTree, size_t LeafSize, bool AllowRemovals> class KDTreeModelConfiguration; /** Helper class for KDTreeModel. */ template class KDTreeModelConfiguration { public: typedef int Exponent; typedef ::Monomial Monomial; typedef Monomial Entry; KDTreeModelConfiguration (size_t varCount, bool sortOnInsert, bool useDivisorCache, double rebuildRatio, size_t minRebuild): _varCount(varCount), _sortOnInsert(sortOnInsert), _useDivisorCache(useDivisorCache), _useAutomaticRebuild((rebuildRatio > 0.0 || minRebuild > 0) && UDM), _rebuildRatio(rebuildRatio), _minRebuild(minRebuild), _expQueryCount(0) { ASSERT(rebuildRatio >= 0); } size_t getVarCount() const {return _varCount;} bool getSortOnInsert() const {return _sortOnInsert;} Exponent getExponent(const Monomial& monomial, size_t var) const { ++_expQueryCount; ASSERT(var < monomial.size()); return monomial[var]; } NO_PINLINE bool divides(const Monomial& a, const Monomial& b) const { for (size_t var = 0; var < getVarCount(); ++var) if (getExponent(b, var) < getExponent(a, var)) return false; return true; } bool isLessThan(const Monomial& a, const Monomial& b) const { for (size_t var = 0; var < getVarCount(); ++var) { if (getExponent(a, var) < getExponent(b, var)) return true; if (getExponent(b, var) < getExponent(a, var)) return false; } return false; } size_t getLeafSize() const {return LeafSize;} bool getUseDivisorCache() const {return _useDivisorCache;} bool getDoAutomaticRebuilds() const {return _useAutomaticRebuild;} double getRebuildRatio() const {return _rebuildRatio;} size_t getRebuildMin() const {return _minRebuild;} static const bool UseDivMask = UDM; static const bool UseTreeDivMask = UTDM; static const bool PackedTree = PT; static const size_t LeafSize = LS; static const bool AllowRemovals = AR; unsigned long long getExpQueryCount() const {return _expQueryCount;} private: const size_t _varCount; const bool _sortOnInsert; const bool _useDivisorCache; const bool _useAutomaticRebuild; const double _rebuildRatio; const size_t _minRebuild; mutable unsigned long long _expQueryCount; }; /** An instantiation of the capabilities of KDTree. */ template< bool UseDivMask, bool UseTreeDivMask, bool PackedTree, size_t LeafSize, bool AllowRemovals > class KDTreeModel { private: typedef KDTreeModelConfiguration C; typedef mathic::KDTree Finder; public: typedef typename Finder::Monomial Monomial; typedef typename Finder::Entry Entry; KDTreeModel(size_t varCount, bool minimizeOnInsert, bool sortOnInsert, bool useDivisorCache, double rebuildRatio, size_t minRebuild): _finder(C(varCount, sortOnInsert, useDivisorCache, rebuildRatio, minRebuild)), _minimizeOnInsert(minimizeOnInsert) { ASSERT(!UseTreeDivMask || UseDivMask); } void insert(const Entry& entry); template void insert(const Entry& entry, MultipleOutput& removed); Entry* findDivisor(const Monomial& monomial) { return _finder.findDivisor(monomial); } const Entry* findDivisor(const Monomial& monomial) const { return _finder.findDivisor(monomial); } std::string getName() const; template void findAllDivisors(const Monomial& monomial, DO& out) { _finder.findAllDivisors(monomial, out); } template void findAllDivisors(const Monomial& monomial, DO& out) const { _finder.findAllDivisors(monomial, out); } template void forAll(EO& out) { _finder.forAll(out); } template void forAll(EO& out) const { _finder.forAll(out); } size_t size() const {return _finder.size();} unsigned long long getExpQueryCount() const { return _finder.getConfiguration().getExpQueryCount(); } class Comparer; private: Finder _finder; bool _minimizeOnInsert; }; template inline void KDTreeModel::insert(const Entry& entry) { if (!_minimizeOnInsert) { _finder.insert(entry); return; } if (findDivisor(entry) != 0) return; _finder.removeMultiples(entry); _finder.insert(entry); } template template inline void KDTreeModel:: insert(const Entry& entry, MultipleOutput& removed) { if (!_minimizeOnInsert) { _finder.insert(entry); return; } if (findDivisor(entry) != 0) return; _finder.removeMultiples(entry, removed); _finder.insert(entry); } template inline std::string KDTreeModel::getName() const { return _finder.getName() + (_minimizeOnInsert ? " remin" : " nomin"); } #endif mathic-master/src/divsim/Monomial.h000066400000000000000000000021441311555225300176250ustar00rootroot00000000000000#ifndef MONOMIAL_GUARD #define MONOMIAL_GUARD #include #include class Monomial { public: typedef int Exponent; Monomial(): _exponents(0) {IF_DEBUG(_size = 0);} Monomial(std::vector& v): _exponents(&v[0]) { IF_DEBUG(_size = v.size()); } inline Exponent& operator[](size_t index) { ASSERT(index < _size); return _exponents[index]; } inline const Exponent& operator[](size_t index) const { ASSERT(index < _size); return _exponents[index]; } const Exponent* getPointer() const {return _exponents;} #ifdef DEBUG size_t size() const {return _size;} bool operator==(const Monomial& m) const {return _exponents == m._exponents;} bool operator<(const Monomial& m) const {return _exponents < m._exponents;} #endif private: #ifdef DEBUG size_t _size; #endif Exponent* _exponents; }; inline std::ostream& operator<<(std::ostream& out, const Monomial& monomial) { #ifdef DEBUG out << "(Monomial:"; for (size_t i = 0; i < monomial.size(); ++i) out << ' ' << monomial[i]; out << ')'; #else out << "(Monomial)"; #endif return out; } #endif mathic-master/src/divsim/Simulation.cpp000077500000000000000000000032751311555225300205420ustar00rootroot00000000000000#include "stdinc.h" #include "Simulation.h" #include "mathic/ColumnPrinter.h" #include #include namespace { void makeRandom(std::vector& monomial) { for (size_t var = 0; var < monomial.size(); ++var) monomial[var] = rand() % 1000; } } void Simulation::makeStandard (size_t varCount, size_t inserts, size_t queries, bool findAll) { srand(0); _findAll = findAll; _varCount = varCount; _events.clear(); for (size_t i = 0; i < inserts + queries; ++i) { /*Event event2; event2._type = StateUnknown; _events.push_back(event2);*/ Event event; event._monomial.resize(varCount); makeRandom(event._monomial); event._type = (i <= inserts ? InsertUnknown : QueryUnknown); _events.push_back(event); } } void Simulation::printData(std::ostream& out) const { std::vector sorted(_data); std::sort(sorted.begin(), sorted.end()); out << "*** Simulation outcome for " << _repeats << " repeats ***" << std::endl; mic::ColumnPrinter pr; pr.addColumn(true); pr.addColumn(false, " ", "ms"); pr.addColumn(false, " ", "eqs"); for (std::vector::const_iterator it = sorted.begin(); it != sorted.end(); ++it) { pr[0] << it->_name << '\n'; pr[1] << mic::ColumnPrinter::commafy(it->_mseconds) << '\n'; pr[2] << mic::ColumnPrinter::commafy(it->_expQueryCount) << '\n'; } pr.print(out); } void Simulation::SimData::print(std::ostream& out) { out << _name << " " << mic::ColumnPrinter::commafy(_mseconds) << " ms" << " " << mic::ColumnPrinter::commafy(_expQueryCount) << " eqs" << '\n'; } bool Simulation::SimData::operator<(const SimData& sd) const { return _mseconds < sd._mseconds; } mathic-master/src/divsim/Simulation.h000077500000000000000000000206161311555225300202050ustar00rootroot00000000000000#ifndef SIMULATION_GUARD #define SIMULATION_GUARD #include "Monomial.h" #include "mathic/Timer.h" #include #include #include #include class Simulation { public: Simulation(size_t repeats, bool printPartialData): _repeats(repeats), _printPartialData(printPartialData), _simType("none") {} void makeStandard(size_t varCount, size_t inserts, size_t queries, bool findAll); template void run(); template void run(const Param1& param1); template void run(const Param1& param1, const Param2& param2); template void run(const Param1& param1, const Param2& param2, const Param3& param3); template void run(const P1& p1, const P2& p2, const P3& param3, const P4& param4); template void run(const P1& p1, const P2& p2, const P3& param3, const P4& param4, const P5& p5); template void run(const P1& p1, const P2& p2, const P3& param3, const P4& param4, const P5& p5, const P6& p6); void printData(std::ostream& out) const; private: struct SimData { bool operator<(const SimData& sd) const; void print(std::ostream& out); std::string _name; unsigned long _mseconds; unsigned long long _expQueryCount; }; template void run(DivFinder& finder); enum EventType { InsertUnknown, InsertKnown, QueryNoDivisor, QueryHasDivisor, QueryUnknown, StateUnknown, StateKnown }; struct Event { EventType _type; std::vector _monomial; std::vector _state; #ifdef DEBUG std::vector _allMonomials; #else size_t _monomialCount; #endif }; class MonomialStore; bool _findAll; std::vector _events; std::vector _data; size_t _varCount; size_t _repeats; bool _printPartialData; std::string _simType; }; template void Simulation::run() { DivFinder finder(_varCount); run(finder); } template void Simulation::run(const Param1& param1) { DivFinder finder(_varCount, param1); run(finder); } template void Simulation::run(const Param1& param1, const Param2& param2) { DivFinder finder(_varCount, param1, param2); run(finder); } template void Simulation::run (const Param1& param1, const Param2& param2, const Param3& param3) { DivFinder finder(_varCount, param1, param2, param3); run(finder); } template void Simulation::run (const P1& param1, const P2& param2, const P3& param3, const P4& param4) { DivFinder finder(_varCount, param1, param2, param3, param4); run(finder); } template void Simulation::run (const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5) { DivFinder finder(_varCount, p1, p2, p3, p4, p5); run(finder); } template void Simulation::run (const P1& p1, const P2& p2, const P3& p3, const P4& p4, const P5& p5, const P6& p6) { DivFinder finder(_varCount, p1, p2, p3, p4, p5, p6); run(finder); } class Simulation::MonomialStore { public: MonomialStore() {clear();} void clear() { #ifdef DEBUG _monomials.clear(); #else _monomialCount = 0; #endif } void push_back(const Monomial& monomial) { proceed(monomial); } bool proceed(const Monomial& monomial) { #ifdef DEBUG _monomials.push_back(monomial); #else ++_monomialCount; #endif return true; } template void checkInsert(Event& e, const Finder& finder) { #ifdef DEBUG std::sort(_monomials.begin(), _monomials.end()); #endif if (e._type == InsertUnknown) { #ifdef DEBUG e._allMonomials.clear(); for (size_t i = 0; i < _monomials.size(); ++i) e._allMonomials.push_back(_monomials[i]); #else e._monomialCount = _monomialCount; #endif e._type = InsertKnown; } else { #ifdef DEBUG ASSERT(_monomials == e._allMonomials); #else if (_monomialCount != e._monomialCount) { std::cerr << "Finder \"" << finder.getName() << "\" found incorrect number of monomials." << std::endl; std::exit(1); } #endif } } template void checkQuery(Event& e, const Finder& finder) { #ifdef DEBUG for (size_t d = 0; d < _monomials.size(); ++d) { for (size_t var = 0; var < e._monomial.size(); ++var) { ASSERT(_monomials[d][var] <= e._monomial[var]); } } std::sort(_monomials.begin(), _monomials.end()); #endif if (e._type == QueryUnknown) { bool noMonomials; #ifdef DEBUG e._allMonomials.clear(); for (size_t i = 0; i < _monomials.size(); ++i) e._allMonomials.push_back(_monomials[i]); noMonomials = _monomials.empty(); #else e._monomialCount = _monomialCount; noMonomials = _monomialCount == 0; #endif e._type = noMonomials ? QueryNoDivisor : QueryHasDivisor; } else { #ifdef DEBUG for (size_t i = 0; i < _monomials.size(); ++i) ASSERT(_monomials[i] == e._allMonomials[i]); #else if (_monomialCount != e._monomialCount) { std::cerr << "Finder \"" << finder.getName() << "\" found incorrect number of monomials." << std::endl; std::exit(1); } #endif } } private: #ifdef DEBUG std::vector _monomials; #else size_t _monomialCount; #endif }; struct ForAll { public: ForAll(std::vector& entries): _entries(entries) {} bool proceed(const Monomial& m) { _entries.push_back(m.getPointer()); return true; } private: std::vector& _entries; }; template void Simulation::run(DivFinder& finder) { mic::Timer timer; std::vector divisors; std::vector tmp; for (size_t step = 0; step < _repeats; ++step) { for (size_t i = 0; i < _events.size(); ++i) { Event& e = _events[i]; if (e._type == InsertKnown || e._type == InsertUnknown) { divisors.clear(); MonomialStore store; if (0) { // here to make sure it compiles, also easy to switch to checking this instead. finder.insert(e._monomial); } else finder.insert(e._monomial, store); store.checkInsert(e, finder); } else if (e._type == StateUnknown || e._type == StateKnown) { tmp.clear(); ForAll forAll(tmp); finder.forAll(forAll); if (e._type == StateUnknown) { e._type = StateKnown; e._state.swap(tmp); } else { if (e._state != tmp) { std::cerr << "states differ." << std::endl; std::exit(1); } } } else if (!_findAll) { typename DivFinder::Entry* entry = finder.findDivisor(e._monomial); if (entry == 0) { if (e._type == QueryHasDivisor) { std::cerr << "Divisor finder \"" << finder.getName() << "\" failed to find divisor." << std::endl; std::exit(1); } e._type = QueryNoDivisor; } else { #ifdef DEBUG for (size_t var = 0; var < _varCount; ++var) { ASSERT((*entry)[var] <= e._monomial[var]); } #endif if (e._type == QueryNoDivisor) { std::cerr << "Divisor finder \"" << finder.getName() << "\" found incorrect divisor." << std::endl; std::exit(1); } e._type = QueryHasDivisor; } } else { ASSERT(_findAll); divisors.clear(); MonomialStore store; const_cast(finder) // to test const interface .findAllDivisors(e._monomial, store); store.checkQuery(e, finder); } } } SimData data; data._mseconds = (unsigned long)timer.getMilliseconds(); data._name = finder.getName(); data._expQueryCount = finder.getExpQueryCount(); _data.push_back(data); if (_printPartialData) data.print(std::cerr); std::cout << finder.size() << std::endl; } #endif mathic-master/src/divsim/divMain.cpp000077500000000000000000000134771311555225300200120ustar00rootroot00000000000000#include "stdinc.h" #include "DivListModel.h" #include "KDTreeModel.h" #include "Simulation.h" #include "mathic/Timer.h" #include int main() { const size_t repeats = IF_DEBUG(true ? 1 :) 1; Simulation sim(repeats, true); mic::Timer timer; std::cout << "Generating simulation. "; #ifdef DEBUG sim.makeStandard(10, 400, 1000, true); #else sim.makeStandard(10, 5000, 2000000, true); #endif timer.print(std::cout); std::cout << std::endl; #ifndef DEBUG sim.run >(0, 0, 0, 1.0, 1000); sim.run >(0, 0, 0, 1.0, 1000); return 0; sim.run >(1, 0, 0, 0.0, 0); // best tree, no mask sim.run >(1, 0, 0, 0.0, 0); // best tree, no mask sim.run >(1, 0, 0, 1.0, 1000); // best tree, mask sim.run >(1, 0, 0, 1.0, 1000); // best tree, mask sim.run >(1, 1, 0, 0.5, 500); return 0; #endif /* for (int minimizeOnInsert = 1; minimizeOnInsert <= 1; ++minimizeOnInsert) { for (int order = 0; order <= 2; ++order) { bool moveDivisorToFront = (order == 1); bool sortOnInsert = (order == 2); sim.run > (minimizeOnInsert, moveDivisorToFront, sortOnInsert); sim.run > (minimizeOnInsert, moveDivisorToFront, sortOnInsert); } } //*/ //sim.run >(1, 0, 1, 0.0, 0); // best array, no mask /* sim.run >(1, 0, 0) sim.run >(1, 1, 0); sim.run >(1, 0, 1); sim.run >(1, 0, 0); sim.run >(1, 1, 0); sim.run >(1, 0, 1); //*/ sim.run >(0, 0, 0, 0.0, 0); sim.run >(0, 1, 0, 0.5, 500); for (int mini = 0; mini <= 0; ++mini) { for (int sortOnInsert = 0; sortOnInsert <= 1; ++sortOnInsert) { for (int useDivCache = 0; useDivCache <= 1; ++useDivCache) { sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); sim.run >(mini,sortOnInsert,useDivCache, 0.5, 10); /* for (size_t leafSize = 5; leafSize <= 15; leafSize += 5) for (size_t start = 0; start <= 0; start += 200) for (double ratio = 0; ratio < 0.1; ratio += 0.2) sim.run >(leafSize, mini,sortOnInsert,useDivisorCache, ratio, start); //*/ /*sim.run >(8, mini,sortOnInsert,useDivisorCache, 0, 0); sim.run >(8, mini,sortOnInsert,useDivisorCache, 0, 0); sim.run >(20, mini,sortOnInsert,useDivisorCache, 0, 0); sim.run >(20, mini,sortOnInsert,useDivisorCache, 0, 0); sim.run >(40, mini,sortOnInsert,useDivisorCache, 0, 0); sim.run >(40, mini,sortOnInsert,useDivisorCache, 0, 0); sim.run >(60, mini,sortOnInsert,useDivisorCache, 0, 0); sim.run >(60, mini,sortOnInsert,useDivisorCache, 0, 0);*/ /* sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 2000); sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 4000); sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 6000); sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 6000); sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 8000); sim.run >(10, mini,sortOnInsert,useDivisorCache, 0.001, 10000);*/ //sim.run(10, mini,sortOnInsert,useDivisorCache, 4, 2000); //sim.run(20, mini,sortOnInsert,useDivisorCache, 0.75, 2000); //sim.run(8, mini,sortOnInsert,useDivisorCache, 0.75, 2000); } } } //*/ /* for (int mini = 1; mini <= 1; ++mini) { for (int noneFrontSort = 0; noneFrontSort <= 2; ++noneFrontSort) { bool tof = (noneFrontSort == 1); bool sort = (noneFrontSort == 2); for (double ratio = 0.5; ratio < 0.51; ratio += 0.1) for (size_t start = 500; start <= 500; start += 100) sim.run >(mini, tof, sort, ratio, start); } } //*/ /* best for single query from best to worst sim.run >(40, 1, 0, 0, 1.0, 1000); // best tree, mask sim.run >(15, 1, 0, 0, 0.0, 0); // best tree, no mask sim.run >(1, 1, 0, 0.5, 500); // best array, mask sim.run >(1, 1, 0, 0.5, 500); // should be best linked, mask sim.run >(1, 0, 1, 0.0, 0); // best array, no mask sim.run >(1, 0, 1, 0.0, 0); // best linked, no mask //*/ /* base div lists sim.run >(1, 0, 0, 0.0, 0); // base array sim.run >(1, 0, 0, 0.0, 0); // base linked //*/ std::cout << "\n\n"; sim.printData(std::cout); return 0; } mathic-master/src/divsim/divMain.h000077500000000000000000000001271311555225300174430ustar00rootroot00000000000000#ifndef MATHIC_DIV_MAIN_GUARD #define MATHIC_DIV_MAIN_GUARD int main(); #endif mathic-master/src/divsim/stdinc.h000077500000000000000000000030621311555225300173410ustar00rootroot00000000000000#ifdef STDINC_GUARD #error stdinc.h included twice #endif #define STDINC_GUARD #ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++. #pragma warning (push, 1) // Reduce warning level for GMP headers. #endif #ifdef PROFILE #define NO_PINLINE NO_INLINE #else #define NO_PINLINE #endif #ifndef _MSC_VER #define NO_INLINE __attribute__ ((noinline)) #endif #ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++. #define NO_INLINE __declspec(noinline) #pragma warning (pop) // Go back to previous warning level. #pragma warning (disable: 4996) // std::copy is flagged as dangerous. #pragma warning (disable: 4290) // VC++ ignores throw () specification. #pragma warning (disable: 4127) // Warns about using "while (true)". #pragma warning (disable: 4100) // Warns about unused parameters. #pragma warning (disable: 4800) // Warns on int to bool conversion. #pragma warning (disable: 4146) // Warns on unary minus on unsigned (bit trick) // This warning warns about using the this pointer in base member // initializer lists. This is a pretty good warning as that can // obviously easily go wrong, but it is pretty useful to do as well, // so the warning is turned off. #pragma warning (disable: 4355) #ifdef _DEBUG #define DEBUG #endif #endif #include #include #ifdef DEBUG #include // Useful for debugging. #define PRINT #include #define ASSERT(X) assert(X); #define IF_DEBUG(X) X #else #define ASSERT(X) #define IF_DEBUG(X) #endif static const size_t BitsPerByte = 8; static const size_t MemoryAlignment = sizeof(void*); mathic-master/src/mathic.cpp000077500000000000000000000001671311555225300163650ustar00rootroot00000000000000#include "mathic.h" extern "C" { void libmathicIsPresent(void) {} char MATHIC_VERSION_STRING[] = VERSION; } mathic-master/src/mathic.h000077500000000000000000000022111311555225300160220ustar00rootroot00000000000000// Include this file to pull in all external Mathic files // utilities #include "mathic/Timer.h" #include "mathic/ColumnPrinter.h" #include "mathic/error.h" // other data structures #include "mathic/BitTriangle.h" #include "mathic/HashTable.h" // divisor query data structures #include "mathic/DivList.h" #include "mathic/KDTree.h" // priority queue data structures #include "mathic/TourTree.h" #include "mathic/StlSet.h" #include "mathic/Heap.h" #include "mathic/Geobucket.h" #include "mathic/PairQueue.h" // CLI package #include "mathic/Action.h" #include "mathic/BoolParameter.h" #include "mathic/CliParameter.h" #include "mathic/CliParser.h" #include "mathic/HelpAction.h" #include "mathic/IntegerParameter.h" #include "mathic/StringParameter.h" #include "mathic/display.h" extern "C" { // Put a C function in the library so that it can be detected by the autoconf // macro AC_CHECK_LIB. That macro can only check for libraries that contain // at least one C function. void libmathicIsPresent(void); // This function does nothing. extern char MATHIC_VERSION_STRING[]; } #define MATHIC_VERSION VERSION mathic-master/src/mathic/000077500000000000000000000000001311555225300156525ustar00rootroot00000000000000mathic-master/src/mathic/Action.cpp000077500000000000000000000005151311555225300175770ustar00rootroot00000000000000#include "Action.h" #include "error.h" namespace mathic { Action::~Action() { } void Action::directOptions( std::vector tokens, CliParser& parser ) { if (!tokens.empty()) { reportError("Expected a dash (-) to indicate an option when reading \"" + tokens.front() + "\"."); } } } mathic-master/src/mathic/Action.h000077500000000000000000000023571311555225300172520ustar00rootroot00000000000000#ifndef MATHIC_ACTION_GUARD #define MATHIC_ACTION_GUARD #include "stdinc.h" #include #include namespace mathic { class CliParameter; class CliParser; class Action { public: virtual ~Action(); // Called with tokens that precede any option of the // form -option. The default is to give an error saying // that a dash was expected if tokens is not empty. virtual void directOptions (std::vector tokens, CliParser& parser); // Do what it is this action does. virtual void performAction() = 0; // *************************************** // **** Information provided by each Action // The name of the action. virtual const char* name() const = 0; // More detailed explanation of what the action does. virtual const char* description() const = 0; // One-line summary of the description. virtual const char* shortDescription() const = 0; // Append the parameters for this action to the passed-in container. // Do not clear the passed-in container. virtual void pushBackParameters(std::vector& parameters) = 0; // Return true if this class is HelpAction. virtual bool isHelpAction() const {return false;} }; } #endif mathic-master/src/mathic/BinaryKDTree.h000077500000000000000000000570341311555225300203220ustar00rootroot00000000000000#ifndef MATHIC_BINARY_K_D_TREE_GUARD #define MATHIC_BINARY_K_D_TREE_GUARD #include "stdinc.h" #include "DivMask.h" #include "KDEntryArray.h" #include #include namespace mathic { template class BinaryKDTree { public: typedef typename C::Monomial Monomial; typedef typename C::Entry Entry; typedef typename C::Exponent Exponent; typedef typename DivMask::Extender ExtEntry; typedef typename DivMask::Extender ExtMonoRef; typedef typename DivMask::Calculator DivMaskCalculator; struct ExpOrder { ExpOrder(size_t var, const C& conf): _var(var), _conf(conf) {} bool operator()(const ExtEntry& a, const ExtEntry& b) const { return _conf.getExponent(a.get(), _var) < _conf.getExponent(b.get(), _var); } private: const size_t _var; const C& _conf; }; private: /** A helper class for KDTree. A node in the tree. The ExtEntry comes from the KdTree. */ class KDTreeNode; /** A helper class for KDTree. An interior node in the tree. The ExtEntry comes from the KdTree. @todo: rename to KDTreeInternal. */ class KDTreeInterior; /** A helper class for KDTree. Represents a leaf in the tree. Leaves hold the monomials. The Configuration is as for KdTree. The ExtEntry comes from the KdTree. */ class KDTreeLeaf; typedef KDTreeNode Node; typedef KDTreeInterior Interior; typedef KDTreeLeaf Leaf; typedef C Configuration; static const bool UseDivMask = C::UseDivMask; class KDTreeNode { public: bool isLeaf() const {return _isLeaf;} const Leaf& asLeaf() const { MATHIC_ASSERT(isLeaf()); return static_cast(*this); } Leaf& asLeaf() { MATHIC_ASSERT(isLeaf()); return static_cast(*this); } bool isInterior() const {return !isLeaf();} const Interior& asInterior() const { MATHIC_ASSERT(isInterior()); return static_cast(*this); } Interior& asInterior() { MATHIC_ASSERT(isInterior()); return static_cast(*this); } protected: KDTreeNode(bool leaf): _isLeaf(leaf) {} private: KDTreeNode(const KDTreeNode&); // unavailable void operator=(const KDTreeNode&); // unavailable class SplitEqualOrLess; const bool _isLeaf; }; class KDTreeInterior : public KDTreeNode, public mathic::DivMask::HasDivMask { public: typedef typename C::Exponent Exponent; typedef KDTreeInterior Interior; typedef KDTreeLeaf Leaf; typedef KDTreeNode Node; KDTreeInterior (Node& equalOrLess, Node& strictlyGreater, size_t var, Exponent exponent): Node(false), _equalOrLess(&equalOrLess), _strictlyGreater(&strictlyGreater), _var(var), _exponent(exponent) { } KDTreeInterior (size_t var, Exponent exponent): Node(false), _equalOrLess(0), _strictlyGreater(0), _var(var), _exponent(exponent) { } size_t getVar() const {return _var;} Exponent getExponent() const {return _exponent;} Node& getEqualOrLess() {return *_equalOrLess;} const Node& getEqualOrLess() const {return *_equalOrLess;} void setEqualOrLess(Node* equalOrLess) {_equalOrLess = equalOrLess;} Node& getStrictlyGreater() {return *_strictlyGreater;} const Node& getStrictlyGreater() const {return *_strictlyGreater;} void setStrictlyGreater(Node* strictlyGreater) { _strictlyGreater = strictlyGreater; } Node& getChildFor(const ExtEntry& entry, const C& conf) { if (getExponent() < conf.getExponent(entry.get(), getVar())) return getStrictlyGreater(); else return getEqualOrLess(); } using DivMask::HasDivMask::updateToLowerBound; void updateToLowerBound(Node& node) { if (!C::UseTreeDivMask) return; if (node.isLeaf()) DivMask::HasDivMask:: updateToLowerBound(node.asLeaf().entries()); else DivMask::HasDivMask:: updateToLowerBound(node.asInterior()); } private: Node* _equalOrLess; Node* _strictlyGreater; size_t _var; Exponent _exponent; }; class KDTreeLeaf : public KDTreeNode { typedef KDTreeInterior Interior; typedef KDTreeLeaf Leaf; typedef KDTreeNode Node; public: typedef typename C::Monomial Monomial; typedef ExtEntry* iterator; typedef const ExtEntry* const_iterator; typedef const ExtEntry& const_reference; typedef ExtEntry value_type; typedef DivMask::Calculator DivMaskCalculator; KDTreeLeaf(memt::Arena& arena, const C& conf); /** Copies Entry's in [begin, end) into the new leaf after calculating div mask if using those. */ template KDTreeLeaf(Iter begin, Iter end, memt::Arena& arena, const DivMaskCalculator& calc, const C& conf); /** Copies ExtEntry's [begin, end) into the new leaf. */ template KDTreeLeaf(Iter begin, Iter end, memt::Arena& arena, const C& conf); mathic::KDEntryArray& entries() {return _entries;} const KDEntryArray& entries() const {return _entries;} /** When this node is full, call this to insert an element. It splits the elements in this noe into two leaves and returns a new interior node that is the parent of them. */ Interior& splitInsert(const ExtEntry& entry, Interior* parent, memt::Arena& arena, const C& conf); private: KDEntryArray _entries; }; public: typedef typename Leaf::iterator LeafIt; public: BinaryKDTree(const C& configuration); ~BinaryKDTree(); template size_t removeMultiples(const ExtMonoRef& monomial, MultipleOutput& out); bool removeElement(const Monomial& monomial); void insert(const ExtEntry& entry); template void reset(Iter begin, Iter end, const DivMaskCalculator& calc); inline Entry* findDivisor(const ExtMonoRef& monomial); template inline void findAllDivisors (const ExtMonoRef& monomial, DivisorOutput& out); template inline void findAllMultiples (const ExtMonoRef& monomial, Output& out); template void forAll(EntryOutput& out); void clear(); size_t getMemoryUse() const; C& getConfiguration() {return _conf;} void print(std::ostream& out) const; /// Asserts internal invariants if asserts are turned on. bool debugIsValid() const; private: BinaryKDTree(const BinaryKDTree&); // unavailable void operator=(const BinaryKDTree&); // unavailable template struct InsertTodo { Iter begin; Iter end; Interior* parent; }; memt::Arena _arena; // Everything permanent allocated from here. C _conf; // User supplied configuration. mutable std::vector _tmp; // For navigating the tree. Node* _root; // Root of the tree. Can be null! }; template BinaryKDTree::BinaryKDTree(const C& configuration): _conf(configuration), _root(0) { MATHIC_ASSERT(C::LeafSize > 0); MATHIC_ASSERT(debugIsValid()); } template BinaryKDTree::~BinaryKDTree() { clear(); } template template size_t BinaryKDTree::removeMultiples(const ExtMonoRef& extMonomial, MO& out) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return 0; size_t removedCount = 0; Node* node = _root; while (true) { while (node->isInterior()) { Interior& interior = node->asInterior(); if (!(interior.getExponent() < _conf.getExponent(extMonomial.get(), interior.getVar()))) _tmp.push_back(&interior.getEqualOrLess()); node = &interior.getStrictlyGreater(); } MATHIC_ASSERT(node->isLeaf()); removedCount += node->asLeaf().entries().removeMultiples(extMonomial, out, _conf); if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); MATHIC_ASSERT(debugIsValid()); return removedCount; } template bool BinaryKDTree::removeElement(const Monomial& monomial) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return 0; Node* node = _root; while (node->isInterior()) node = node->asInterior().getChildFor(monomial, _conf); const bool value = node->asLeaf().removeElement(monomial); MATHIC_ASSERT(debugIsValid()); return value; } template void BinaryKDTree::insert(const ExtEntry& extEntry) { Interior* parent = 0; if (_root == 0) _root = new (_arena.allocObjectNoCon()) Leaf(_arena, _conf); Node* node = _root; while (node->isInterior()) { parent = &node->asInterior(); if (C::UseTreeDivMask) parent->updateToLowerBound(extEntry); node = &parent->getChildFor(extEntry, _conf); } Leaf* leaf = &node->asLeaf(); MATHIC_ASSERT(leaf->entries().size() <= C::LeafSize); if (leaf->entries().size() == C::LeafSize) { Interior& interior = leaf->splitInsert(extEntry, parent, _arena, _conf); if (parent == 0) { MATHIC_ASSERT(leaf == _root); _root = &interior; } } else { MATHIC_ASSERT(leaf->entries().size() < C::LeafSize); leaf->entries().insert(extEntry, _conf); MATHIC_ASSERT(debugIsValid()); } } template template void BinaryKDTree::reset(Iter insertBegin, Iter insertEnd, const DivMaskCalculator& calc) { clear(); if (insertBegin == insertEnd) return; typedef InsertTodo Task; typedef std::vector TaskCont; TaskCont todo; Interior* parent = 0; bool isEqualOrLessChild = false; while (true) { Node* node = 0; const size_t insertCount = std::distance(insertBegin, insertEnd); const bool isLeaf = (insertCount <= C::LeafSize); if (isLeaf) node = new (_arena.allocObjectNoCon()) Leaf(insertBegin, insertEnd, _arena, calc, _conf); else { size_t var = (parent == 0 ? static_cast(-1) : parent->getVar()); Exponent exp; Iter middle = KDEntryArray:: split(insertBegin, insertEnd, var, exp, _conf); Interior* interior = new (_arena.allocObjectNoCon()) Interior(var, exp); MATHIC_ASSERT(middle != insertBegin && middle != insertEnd); // push strictly-greater on todo Task task; task.begin = middle; task.end = insertEnd; task.parent = interior; todo.push_back(task); // set up equal-or-less insertEnd = middle; node = interior; } if (parent == 0) { MATHIC_ASSERT(_root == 0); _root = node; } else if (isEqualOrLessChild) parent->setEqualOrLess(node); else parent->setStrictlyGreater(node); if (isLeaf) { // grab next item from todo if (todo.empty()) break; Task task = todo.back(); todo.pop_back(); insertBegin = task.begin; insertEnd = task.end; parent = task.parent; // only strictlyGreater goes on todo isEqualOrLessChild = false; } else { isEqualOrLessChild = true; parent = &node->asInterior(); // continue with equal-or-less as next item } } MATHIC_ASSERT(_root != 0); if (C::UseTreeDivMask) { // record nodes in tree using breadth first search typedef std::vector NodeCont; NodeCont nodes; if (_root->isInterior()) nodes.push_back(&_root->asInterior()); for (size_t i = 0; i < nodes.size(); ++i) { Interior* node = nodes[i]; if (node->getEqualOrLess().isInterior()) nodes.push_back(&node->getEqualOrLess().asInterior()); if (node->getStrictlyGreater().isInterior()) nodes.push_back(&node->getStrictlyGreater().asInterior()); } // compute div masks in reverse order of breath first search typename NodeCont::reverse_iterator it = nodes.rbegin(); typename NodeCont::reverse_iterator end = nodes.rend(); for (; it != end; ++it) { Interior* node = *it; node->updateToLowerBound(node->getEqualOrLess()); node->updateToLowerBound(node->getStrictlyGreater()); } } MATHIC_ASSERT(debugIsValid()); } template typename BinaryKDTree::Entry* BinaryKDTree::findDivisor (const ExtMonoRef& extMonomial) { MATHIC_ASSERT(debugIsValid()); MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return 0; Node* node = _root; while (true) { while (node->isInterior()) { Interior& interior = node->asInterior(); if (C::UseTreeDivMask && !interior.getDivMask().canDivide(extMonomial.getDivMask())) goto next; if (interior.getExponent() < _conf.getExponent(extMonomial.get(), interior.getVar())) _tmp.push_back(&interior.getStrictlyGreater()); node = &interior.getEqualOrLess(); } { MATHIC_ASSERT(node->isLeaf()); Leaf& leaf = node->asLeaf(); LeafIt leafIt = leaf.entries().findDivisor(extMonomial, _conf); if (leafIt != leaf.entries().end()) { MATHIC_ASSERT(_conf.divides(leafIt->get(), extMonomial.get())); _tmp.clear(); return &leafIt->get(); } } next: if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); return 0; } template template void BinaryKDTree::findAllDivisors(const ExtMonoRef& extMonomial, DO& output) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return; Node* node = _root; while (true) { while (node->isInterior()) { Interior& interior = node->asInterior(); if (C::UseTreeDivMask && !interior.getDivMask().canDivide(extMonomial.getDivMask())) goto next; if (interior.getExponent() < _conf.getExponent(extMonomial.get(), interior.getVar())) _tmp.push_back(&interior.getStrictlyGreater()); node = &interior.getEqualOrLess(); } MATHIC_ASSERT(node->isLeaf()); { Leaf& leaf = node->asLeaf(); if (!leaf.entries().findAllDivisors(extMonomial, output, _conf)) { _tmp.clear(); break; } } next: if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); } template template void BinaryKDTree::findAllMultiples(const ExtMonoRef& extMonomial, DO& output) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return; Node* node = _root; while (true) { while (node->isInterior()) { Interior& interior = node->asInterior(); if (!(interior.getExponent() < _conf.getExponent(extMonomial.get(), interior.getVar()))) _tmp.push_back(&interior.getEqualOrLess()); node = &interior.getStrictlyGreater(); } MATHIC_ASSERT(node->isLeaf()); { Leaf& leaf = node->asLeaf(); if (!leaf.entries().findAllMultiples(extMonomial, output, _conf)) { _tmp.clear(); break; } } //next: if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); } template template void BinaryKDTree::forAll(EO& output) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return; Node* node = _root; while (true) { while (node->isInterior()) { Interior& interior = node->asInterior(); _tmp.push_back(&interior.getStrictlyGreater()); node = &interior.getEqualOrLess(); } MATHIC_ASSERT(node->isLeaf()); Leaf& leaf = node->asLeaf(); if (!leaf.entries().forAll(output)) { _tmp.clear(); break; } if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); } template void BinaryKDTree::clear() { MATHIC_ASSERT(_tmp.empty()); // Call Entry destructors if (_root != 0) _tmp.push_back(_root); while (!_tmp.empty()) { Node* node = _tmp.back(); _tmp.pop_back(); while (node->isInterior()) { _tmp.push_back(&node->asInterior().getStrictlyGreater()); node = &node->asInterior().getEqualOrLess(); } MATHIC_ASSERT(node->isLeaf()); node->asLeaf().entries().clear(); } _arena.freeAllAllocs(); _root = 0; } template size_t BinaryKDTree::getMemoryUse() const { size_t sum = _arena.getMemoryUse(); sum += _tmp.capacity() * sizeof(_tmp.front()); return sum; } template void BinaryKDTree::print(std::ostream& out) const { out << "<<<<<<<< BinaryKDTree >>>>>>>>\n"; MATHIC_ASSERT(_tmp.empty()); if (_root != 0) { Node* node = _root; while (true) { if (node->isInterior()) { Interior& interior = node->asInterior(); out << "**** Interior Node " << &interior << '\n'; out << "Split on " << interior.getVar() << '^' << interior.getExponent() << '\n'; out << "Child <=: " << &interior.getEqualOrLess() << '\n'; out << "Child > : " << &interior.getStrictlyGreater() << '\n'; out << '\n'; _tmp.push_back(&interior.getEqualOrLess()); _tmp.push_back(&interior.getStrictlyGreater()); } else { Leaf& leaf = node->asLeaf(); out << "**** Leaf Node " << &leaf << '\n'; for (size_t i = 0; i < leaf.entries().size(); ++i) { out << "Entry " << (i + 1) << ": " << leaf.entries().begin()[i].get() << '\n'; } out << '\n'; } if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); } } template bool BinaryKDTree::debugIsValid() const { #ifndef MATHIC_DEBUG return true; #else MATHIC_ASSERT(_tmp.empty()); MATHIC_ASSERT(!_conf.getDoAutomaticRebuilds() || _conf.getRebuildRatio() > 0); if (_root == 0) return true; // record all nodes std::vector nodes; nodes.push_back(_root); size_t sizeSum = 0; for (size_t i = 0; i < nodes.size(); ++i) { Node* node = nodes[i]; if (node->isInterior()) { MATHIC_ASSERT(node->asInterior().getVar() < _conf.getVarCount()); nodes.push_back(&node->asInterior().getStrictlyGreater()); nodes.push_back(&node->asInterior().getEqualOrLess()); } else sizeSum += node->asLeaf().entries().size(); } // check the recorded nodes MATHIC_ASSERT(_tmp.empty()); for (size_t i = 0; i < nodes.size(); ++i) { Node* nodei = nodes[i]; if (nodei->isLeaf()) { MATHIC_ASSERT(nodei->asLeaf().entries().debugIsValid()); continue; } Interior& interior = nodei->asInterior(); size_t var = interior.getVar(); Exponent exp = interior.getExponent(); MATHIC_ASSERT(_tmp.empty()); // check equal or less than sub tree _tmp.push_back(&interior.getEqualOrLess()); while (!_tmp.empty()) { Node* node = _tmp.back(); _tmp.pop_back(); if (C::UseTreeDivMask) { if (node->isInterior()) MATHIC_ASSERT(interior.getDivMask().canDivide(node->asInterior().getDivMask())); else MATHIC_ASSERT(interior.getDivMask().canDivide(node->asLeaf().entries().getDivMask())); } if (node->isInterior()) { _tmp.push_back(&node->asInterior().getStrictlyGreater()); _tmp.push_back(&node->asInterior().getEqualOrLess()); } else { MATHIC_ASSERT(node->asLeaf().entries().allLessThanOrEqualTo(var, exp, _conf)); } } // check strictly greater _tmp.push_back(&interior.getStrictlyGreater()); while (!_tmp.empty()) { Node* node = _tmp.back(); _tmp.pop_back(); if (C::UseTreeDivMask) { if (node->isInterior()) MATHIC_ASSERT(interior.getDivMask().canDivide(node->asInterior().getDivMask())); else MATHIC_ASSERT(interior.getDivMask().canDivide(node->asLeaf().entries().getDivMask())); } if (node->isInterior()) { _tmp.push_back(&node->asInterior().getStrictlyGreater()); _tmp.push_back(&node->asInterior().getEqualOrLess()); } else { MATHIC_ASSERT(node->asLeaf().entries().allStrictlyGreaterThan(var, exp, _conf)); } } } return true; #endif } template BinaryKDTree::KDTreeLeaf::KDTreeLeaf(memt::Arena& arena, const C& conf): Node(true), _entries(arena, conf) {} template template BinaryKDTree::KDTreeLeaf::KDTreeLeaf( Iter begin, Iter end, memt::Arena& arena, const DivMaskCalculator& calc, const C& conf): Node(true), _entries(begin, end, arena, calc, conf) {} template template BinaryKDTree::KDTreeLeaf::KDTreeLeaf( Iter begin, Iter end, memt::Arena& arena, const C& conf): Node(true), _entries(begin, end, arena, conf) {} template class BinaryKDTree::KDTreeNode::SplitEqualOrLess { public: typedef typename C::Exponent Exponent; typedef typename C::Entry Entry; SplitEqualOrLess(size_t var, const Exponent& exp, const C& conf): _var(var), _exp(exp), _conf(conf) {} bool operator()(const Entry& entry) const { return !(_exp < _conf.getExponent(entry, _var)); } private: size_t _var; const Exponent& _exp; const C& _conf; }; template typename BinaryKDTree::KDTreeInterior& BinaryKDTree::KDTreeLeaf::splitInsert(const ExtEntry& extEntry, Interior* parent, memt::Arena& arena, const C& conf) { MATHIC_ASSERT(conf.getVarCount() > 0); MATHIC_ASSERT(entries().size() > 0); size_t var = (parent == 0 ? static_cast(-1) : parent->getVar()); typename C::Exponent exp; iterator middle = KDEntryArray::split (entries().begin(), entries().end(), var, exp, conf, &extEntry); Leaf& other = *new (arena.allocObjectNoCon()) Leaf(middle, entries().end(), arena, conf); while (middle != entries().end()) entries().pop_back(); if (conf.getSortOnInsert()) std::sort(entries().begin(), entries().end(), Comparer(conf)); Interior& interior = *new (arena.allocObjectNoCon()) Interior(*this, other, var, exp); if (C::UseTreeDivMask) { entries().recalculateTreeDivMask(); interior.updateToLowerBound(entries()); interior.updateToLowerBound(other.entries()); } if (parent != 0) { if (&parent->getEqualOrLess() == this) parent->setEqualOrLess(&interior); else { MATHIC_ASSERT(&parent->getStrictlyGreater() == this); parent->setStrictlyGreater(&interior); } } interior.updateToLowerBound(extEntry); Leaf* insertLeaf = &interior.getChildFor(extEntry, conf).asLeaf(); MATHIC_ASSERT(insertLeaf->entries().size() < C::LeafSize); insertLeaf->entries().insert(extEntry, conf); return interior; } } #endif mathic-master/src/mathic/BitTriangle.cpp000077500000000000000000000005771311555225300205760ustar00rootroot00000000000000#include "stdinc.h" #include "BitTriangle.h" namespace mathic { size_t BitTriangle::getMemoryUse() const { size_t sum = mColumns.capacity() * sizeof(mColumns.front()); const size_t stop = mColumns.size(); for (size_t i = 0; i != stop; ++i) { size_t const capacity = mColumns[i].capacity(); sum += (capacity + 7) / 8; // 8 bits per byte rounded up } return sum; } } mathic-master/src/mathic/BitTriangle.h000077500000000000000000000045501311555225300202360ustar00rootroot00000000000000#ifndef MATHIC_BIT_TRIANGLE_GUARD #define MATHIC_BIT_TRIANGLE_GUARD #include "stdinc.h" #include #include namespace mathic { // Object that stores a triangular 2-dimensional array of bits. For example: // // row // 3| // 2| 1 // 1| 0 1 // 0| 0 0 0 // ------- // 0 1 2 3 column // // A bit is addressed by a pair (column, row) where the column goes first. // All valid address pairs have 0 <= row < column < columnCount(). // Columns can be added dynamically. class BitTriangle { public: // Returns how many columns the triangle has size_t columnCount() const {return mColumns.size();} // Returns true if there are no columns in the triangle bool empty() const {return mColumns.empty();} // Adds a new column of the triangle. This increases columnCount() by // one, and the index of the new column is the previous value of // columnCount(). The new bits are all set to false initially. void addColumn() { size_t const oldSize = mColumns.size(); mColumns.resize(oldSize + 1); mColumns[oldSize].resize(oldSize); } // Returns the bit in the given column and row. As this is a triangle it // must be true that row < column. MATHIC_INLINE bool bit(size_t column, size_t row) const { MATHIC_ASSERT(column < columnCount()); MATHIC_ASSERT(row < column); return mColumns[column][row]; } // As bit(), but uses max(x,y) as the column and min(x,y) as the // row. bool bitUnordered(size_t x, size_t y) const { MATHIC_ASSERT(x < columnCount()); MATHIC_ASSERT(y < columnCount()); MATHIC_ASSERT(x != y); if (x < y) std::swap(x, y); return bit(x, y); } // Sets the bit in the given column and row. As this is a triangle // it must be true that column >= row. MATHIC_INLINE void setBit(size_t column, size_t row, bool value) { MATHIC_ASSERT(column < columnCount()); MATHIC_ASSERT(row < column); mColumns[column][row] = value; } // As setBit, but uses max(x,y) as the column and min(x,y) as the // row. void setBitUnordered(size_t x, size_t y, bool value) { MATHIC_ASSERT(x < columnCount()); MATHIC_ASSERT(y < columnCount()); MATHIC_ASSERT(x != y); if (x < y) std::swap(x, y); setBit(x, y, value); } size_t getMemoryUse() const; private: // @todo: use one big array instead of an array of arrays. std::vector > mColumns; }; } #endif mathic-master/src/mathic/BoolParameter.cpp000077500000000000000000000015041311555225300211150ustar00rootroot00000000000000#include "BoolParameter.h" #include "error.h" namespace mathic { BoolParameter::BoolParameter(const std::string& name, const std::string& description, bool defaultValue): CliParameter(name, description), _value(defaultValue) { } std::string BoolParameter::argumentType() const { return "[BOOL]"; } std::string BoolParameter::valueAsString() const { return _value ? "on" : "off"; } void BoolParameter::processArgument(const std::string& argument) { if (argument.empty() || argument == "on") _value = true; else if (argument == "off") _value = false; else { reportError("Option -" + name() + " was given the argument \"" + argument + "\". The only valid arguments are \"on\" and \"off\"."); } } } mathic-master/src/mathic/BoolParameter.h000077500000000000000000000013541311555225300205650ustar00rootroot00000000000000#ifndef MATHIC_BOOL_PARAMETER_GUARD #define MATHIC_BOOL_PARAMETER_GUARD #include "stdinc.h" #include "CliParameter.h" #include #include namespace mathic { class BoolParameter : public CliParameter { public: BoolParameter(const std::string& name, const std::string& description, bool defaultValue); bool value() const {return _value;} void setValue(bool value) {_value = value;} operator bool() const {return value();} void operator=(bool value) {setValue(value);} virtual std::string argumentType() const; virtual std::string valueAsString() const; virtual void processArgument(const std::string& argument); private: bool _value; }; } #endif mathic-master/src/mathic/CliParameter.cpp000077500000000000000000000005431311555225300207330ustar00rootroot00000000000000#include "CliParameter.h" #include "error.h" namespace mathic { CliParameter::CliParameter( const std::string& name, const std::string& description ): _name(name), _description(description) { } CliParameter::~CliParameter() { } void CliParameter::appendToDescription(const std::string& str) { _description += str; } } mathic-master/src/mathic/CliParameter.h000077500000000000000000000012661311555225300204030ustar00rootroot00000000000000#ifndef MATHIC_PARAMETER_GUARD #define MATHIC_PARAMETER_GUARD #include "stdinc.h" #include namespace mathic { class CliParameter { public: virtual ~CliParameter(); const std::string& name() const {return _name;} const std::string& description() const {return _description;} void appendToDescription(const std::string& str); virtual std::string argumentType() const = 0; virtual std::string valueAsString() const = 0; virtual void processArgument(const std::string& argument) = 0; protected: CliParameter(const std::string& name, const std::string& description); private: std::string _name; std::string _description; }; } #endif mathic-master/src/mathic/CliParser.cpp000066400000000000000000000060271311555225300202470ustar00rootroot00000000000000#include "CliParser.h" #include "error.h" #include "CliParameter.h" namespace mathic { namespace { // We are using a NameFactory just for its prefix-finding functionality, so // we set the thing being created to be just void pointers that are null. typedef void* Dummy; typedef NameFactory ParamNames; ParamNames makeParamNames(std::vector params) { ParamNames names("option"); for (size_t i = 0; i < params.size(); ++i) { const auto makeNull = [](){return std::unique_ptr();}; names.registerProduct(params[i]->name(), makeNull); } return names; } } void CliParser::pushBackRegisteredActionNames( std::vector& names ) const { _actions.namesWithPrefix("", names); } CliParser::CliParser(): _actions("action") {} std::unique_ptr CliParser::createActionWithPrefix( const std::string& prefix ) { return createWithPrefix(_actions, prefix); } std::unique_ptr CliParser::parse(int argc, char** argv) { std::vector commandLine(argv, argv + argc); return parse(commandLine); } std::unique_ptr CliParser::parse (const std::vector& commandLine) { if (commandLine.empty()) throwError("No action specified."); std::unique_ptr action = createActionWithPrefix(commandLine[0]); std::vector params; action->pushBackParameters(params); ParamNames paramNames = makeParamNames(params); std::vector options; std::vector directOptions; bool sawDash = false; for (size_t i = 1; i < commandLine.size(); ++i) { if (commandLine[i].empty()) continue; if (commandLine[i][0] == '-') sawDash = true; if (sawDash) options.push_back(commandLine[i]); else directOptions.push_back(commandLine[i]); } action->directOptions(directOptions, *this); size_t i = 1; for (size_t i = 0; i < options.size(); ++i) { std::string const& token = options[i]; if (token[0] != '-') reportError("Expected an option when reading \"" + token + "\", but options start with a dash (-).\n"); std::string noDash(token.begin() + 1, token.end()); std::string name = uniqueNameWithPrefix(paramNames, noDash); std::string optionArgument; if (i + 1 < options.size() && options[i + 1][0] != '-') { optionArgument = options[i + 1]; ++i; } for (std::vector::iterator it = params.begin();; ++it) { if (it == params.end()) { // shouldn't get here as name was recognized above reportInternalError("Processing non-existent option \"" + name + "\"."); } if ((*it)->name() == name) { (*it)->processArgument(optionArgument); break; } } } return action; } } mathic-master/src/mathic/CliParser.h000066400000000000000000000025741311555225300177170ustar00rootroot00000000000000#ifndef MATHIC_CLI_PARSER_GUARD #define MATHIC_CLI_PARSER_GUARD #include "NameFactory.h" #include "Action.h" namespace mathic { class CliParser { public: CliParser(); template void registerAction(const std::string& name); // picks the name up from ConcreteAction::staticName(). template void registerAction(); void registerHelpAction (const std::string& preMessage, const std::string& postMessage); void pushBackRegisteredActionNames( std::vector& names ) const; const std::string& helpPreMessage() const {return _helpPreMessage;} const std::string& helpPostMessage() const {return _helpPostMessage;} std::unique_ptr parse(int argc, char** argv); std::unique_ptr parse(const std::vector& commandLine); std::unique_ptr createActionWithPrefix(const std::string& prefix); private: NameFactory _actions; std::string _helpPreMessage; std::string _helpPostMessage; }; template void CliParser::registerAction(const std::string& name) { nameFactoryRegister(_actions, name); }; template void CliParser::registerAction() { nameFactoryRegister(_actions); }; } #endif mathic-master/src/mathic/ColumnPrinter.cpp000077500000000000000000000164011311555225300211640ustar00rootroot00000000000000#include "ColumnPrinter.h" namespace mathic { namespace { size_t getLineWidth(const std::string& str, size_t pos) { size_t startPos = pos; while (pos < str.size() && str[pos] != '\n' && str[pos] != '\0') ++pos; return pos - startPos; } void printChars(std::ostream& out, size_t howMany, const char c) { while (howMany > 0) { out << c; --howMany; } } } ColumnPrinter::ColumnPrinter(size_t columnCount): _cols() { while (columnCount > 0) { addColumn(); --columnCount; } } void ColumnPrinter::setPrefix(const std::string& prefix) { _prefix = prefix; } std::ostream& ColumnPrinter::addColumn(bool flushLeft, const std::string& prefix, const std::string& suffix) { std::unique_ptr col(new Col()); col->prefix = prefix; col->suffix = suffix; col->flushLeft = flushLeft; _cols.emplace_back(std::move(col)); return _cols.back()->text; } size_t ColumnPrinter::getColumnCount() const { return _cols.size(); } std::ostream& ColumnPrinter::operator[](size_t col) { MATHIC_ASSERT(col < getColumnCount()); return _cols[col]->text; } void ColumnPrinter::repeatToEndOfLine(const char repeatThis, size_t col) { MATHIC_ASSERT(col < getColumnCount()); (*this)[col] << '\0' << repeatThis; } void ColumnPrinter::repeatToEndOfLine(const char repeatThis) { MATHIC_ASSERT(repeatThis != '\n'); for (size_t col = 0; col < getColumnCount(); ++col) repeatToEndOfLine(repeatThis, col); } void ColumnPrinter::print(std::ostream& out) const { // stringstream::str() copies the string, so we need // to extract all the strings and store them to avoid copying // at every access. std::vector texts(getColumnCount()); for (size_t col = 0; col < getColumnCount(); ++col) texts[col] = _cols[col]->text.str(); // Calculate the width of each column. std::vector widths(getColumnCount()); for (size_t col = 0; col < getColumnCount(); ++col) { const auto& text = texts[col]; size_t maxWidth = 0; size_t pos = 0; while (pos < text.size()) { size_t width = getLineWidth(text, pos); if (width > maxWidth) maxWidth = width; // We can't just increment pos unconditionally by width + 1, as // that could result in an overflow. pos += width; if (pos == text.size()) break; if (text[pos] == '\0') { ++pos; if (pos == text.size()) break; ++pos; } else if (text[pos] == '\n') ++pos; } widths[col] = maxWidth; } // Print each row std::vector poses(getColumnCount()); while (true) { bool done = true; for (size_t col = 0; col < getColumnCount(); ++col) { if (poses[col] < texts[col].size()) { done = false; break; } } if (done) break; out << _prefix; for (size_t col = 0; col < getColumnCount(); ++col) { out << _cols[col]->prefix; const std::string& text = texts[col]; size_t& pos = poses[col]; size_t width = getLineWidth(text, pos); char padChar = ' '; if ( pos + width < text.size() && text[pos + width] == '\0' && pos + width + 1 < text.size() ) { padChar = text[pos + width + 1]; } if (!_cols[col]->flushLeft) printChars(out, widths[col] - width, padChar); while (pos < text.size()) { if (text[pos] == '\n') { ++pos; break; } if (text[pos] == '\0') { ++pos; if (pos < text.size()) { MATHIC_ASSERT(text[pos] == padChar); ++pos; } break; } out << text[pos]; ++pos; } if (_cols[col]->flushLeft) printChars(out, widths[col] - width, padChar); out << _cols[col]->suffix; } out << '\n'; } } std::string ColumnPrinter::commafy(const unsigned long long l) { std::stringstream out; out << l; const auto uncomma = out.str(); std::string str; for (size_t i = 0; i < uncomma.size(); ++i) { str += uncomma[i]; if (i != uncomma.size() - 1 && ((uncomma.size() - i) % 3) == 1) str += ','; } return str; } std::string ColumnPrinter::percentInteger( const unsigned long long numerator, const unsigned long long denominator ) { return ratioInteger(numerator * 100, denominator) + '%'; } std::string ColumnPrinter::percentDouble( const double numerator, const double denominator ) { return ratioDouble(numerator * 100, denominator) + '%'; } std::string ColumnPrinter::percentIntegerFixed( const unsigned long long numerator, const unsigned long long denominator ) { auto str = percentInteger(numerator, denominator); const size_t maxSize = 6; MATHIC_ASSERT(maxSize == std::string("100.0%").size()); const auto size = str.size(); if (size > maxSize) return std::move(str); return std::string(maxSize - str.size(), ' ') + std::move(str); } std::string ColumnPrinter::percentDouble(const double ratio) { return oneDecimal(ratio * 100) + '%'; } std::string ColumnPrinter::ratioInteger( const unsigned long long numerator, const unsigned long long denominator ) { if (denominator == 0) return std::string(numerator == 0 ? "0/0" : "?/0"); return oneDecimal(static_cast(numerator) / denominator); } std::string ColumnPrinter::ratioDouble( const double numerator, const double denominator ) { const auto epsilon = 0.000000001; if (-epsilon < denominator && denominator < epsilon) { if (-epsilon < numerator && numerator < epsilon) return "0/0"; else return "?/0"; } return oneDecimal(static_cast(numerator) / denominator); } std::string ColumnPrinter::oneDecimal(const double d) { std::ostringstream out; unsigned long long l = static_cast(d * 10 + 0.5); out << l / 10 << '.' << l % 10; return out.str(); } std::string ColumnPrinter::withSIPrefix(unsigned long long l) { std::ostringstream out; if (l < 1000) out << l; else { const char* const units[] = {"k", "M", "G", "T"}; const size_t unitCount = sizeof(units) / sizeof(*units); double amount = static_cast(l) / 1000.0; size_t i = 0; // the stop condition is at 999.5 because that value will get // rounded to 1000.0. for (i = 0; i < unitCount && amount >= 999.95; ++i) amount /= 1000.0; out << oneDecimal(amount) << units[i]; } return out.str(); } std::string ColumnPrinter::bytesInUnit(const unsigned long long bytes) { std::ostringstream out; if (bytes < 1024) out << bytes << 'B'; else { const char* const units[] = {"kB", "MB", "GB", "TB"}; const size_t unitCount = sizeof(units) / sizeof(*units); double amount = static_cast(bytes) / 1024.0; size_t i = 0; // the stop condition is 1023.95 because that value will get // rounded to 1024.0. for (i = 0; i < unitCount && amount >= 1023.95; ++i) amount /= 1024.0; out << oneDecimal(amount) << units[i]; } return out.str(); } std::ostream& operator<<( std::ostream& out, const ColumnPrinter& printer ) { printer.print(out); return out; } void print(FILE* out, const ColumnPrinter& pr) { std::ostringstream str; str << pr; fputs(str.str().c_str(), out); } } mathic-master/src/mathic/ColumnPrinter.h000077500000000000000000000051571311555225300206370ustar00rootroot00000000000000#ifndef MATHIC_COLUMN_PRINTER_GUARD #define MATHIC_COLUMN_PRINTER_GUARD #include "stdinc.h" #include #include #include #include #include namespace mathic { class ColumnPrinter { public: ColumnPrinter(size_t columnCount = 0); void setPrefix(const std::string& prefix); std::ostream& addColumn( bool flushLeft = true, const std::string& prefix = " ", const std::string& suffix = "" ); size_t getColumnCount() const; std::ostream& operator[](size_t col); /// Inserts a newline after padding the current line with repeatThis /// chars until it fills the column width. void repeatToEndOfLine(const char repeatThis, size_t col); /// Works on all columns. void repeatToEndOfLine(const char repeatThis); void print(std::ostream& out) const; /// Returns "123,456,789" for parameter value 123456789. static std::string commafy(unsigned long long l); /// Returns "123.4G" for parameter value 123456789. So the SI prefix is a /// suffix of the returned string, yet it is still called an SI *prefix* /// because these are usually used as prefixes to units such as in Km. static std::string withSIPrefix(unsigned long long l); /** returns (3,100) as "3.0%". */ static std::string percentInteger( unsigned long long numerator, unsigned long long denominator ); static std::string percentDouble(double numerator, double denominator); /** returns (3,100) as " 3.0%". The string always has the same length for ratios equal to or less than 999.9%. */ static std::string percentIntegerFixed( unsigned long long numerator, unsigned long long denominator); /** returns 0.7565 as "75.7%". */ static std::string percentDouble(double ratio); /** Returns (7,4) as "1.8" */ static std::string ratioInteger( unsigned long long numerator, unsigned long long denominator ); static std::string ratioDouble(double numerator, double denominator); /** Returns d as a string printed to 1 decimal place, rounding up at 0.5 */ static std::string oneDecimal(double d); /** Prints as X bytes, X kilobytes, X megabytes etc. */ static std::string bytesInUnit(unsigned long long bytes); private: struct Col { std::string prefix; std::stringstream text; std::string suffix; bool flushLeft; std::vector > repeatToEndOfLine; }; std::vector> _cols; std::string _prefix; }; std::ostream& operator<<(std::ostream& out, const ColumnPrinter& printer); void print(FILE* out, const ColumnPrinter& pr); } #endif mathic-master/src/mathic/ComTree.h000077500000000000000000000243071311555225300173720ustar00rootroot00000000000000#ifndef MATHIC_COM_TREE_GUARD #define MATHIC_COM_TREE_GUARD #include "stdinc.h" #include namespace mathic { /** This class packs a complete binary tree in a vector. The idea is to have the root at index 1, and then the left child of node n will be at index 2n and the right child will be at index 2n + 1. The corresponding formulas when indexes start at 0 take more computation, so we need a 1-based array so we can't use std::vector. Also, when sizeof(Entry) is a power of 2 it is faster to keep track of i * sizeof(Entry) than directly keeping track of an index i. This doesn't work well when sizeof(Entry) is not a power of two. So we need both possibilities. That is why this class never exposes indexes. Instead you interact with Node objects that serve the role of an index, but the precise value it stores is encapsulated. This way you can't do something like _array[i * sizeof(Entry)] by accident. Client code also does not need to (indeed, can't) be aware of how indexes are calculated, stored and looked up. If FastIndex is false, then Nodes contain an index i. If FastIndex is true, then Nodes contain the byte offset i * sizeof(Entry). FastIndex must be false if sizeof(Entry) is not a power of two. */ template class ComTree { public: class Node; ComTree(size_t initialCapacity = 0); ComTree(const ComTree& tree, size_t minCapacity = 0); ComTree(ComTree&& tree); ~ComTree() { MATHIC_ASSERT(isValid()); delete[](_arrayKeepAlive); } Entry& operator[](Node n); const Entry& operator[](Node n) const; bool empty() const {return _lastLeaf == Node(0);} size_t size() const {return _lastLeaf.getNormalIndex();} size_t capacity() const {return _capacityEnd.getNormalIndex();} Node lastLeaf() const {return _lastLeaf;} void pushBack(const Entry& value); void pushBackWithCapacity(const Entry& value); void popBack(); bool hasFreeCapacity(size_t extraCapacity) const; void increaseCapacity(); void swap(ComTree& tree); class Node { public: Node(): _index(fi ? S : 1) {} // the root node is the default Node parent() const; Node left() const; Node right() const; Node sibling() const; Node leftSibling() const; Node next() const; Node next(size_t count) const; Node prev() const; Node& operator++() {*this = next(); return *this;} bool isRoot() const {return *this == Node();} // Returns a size_t instead of a bool so that the compiler does not // have to convert to bool (this silences a MSVC performance warning). size_t isLeft() const {return fi ? !(_index & S) : !(_index & 1);} // Returns a size_t instead of a bool so that the compiler does not // have to convert to bool (this silences a MSVC performance warning). size_t isRight() const {return fi ? _index & S : _index & 1;} bool operator<(Node node) const {return _index < node._index;} bool operator<=(Node node) const {return _index <= node._index;} bool operator>(Node node) const {return _index > node._index;} bool operator>=(Node node) const {return _index >= node._index;} bool operator==(Node node) const {return _index == node._index;} bool operator!=(Node node) const {return _index != node._index;} //private: friend class ComTree; static const bool fi = FastIndex; static const size_t S = sizeof(Entry); explicit Node(size_t i): _index(i) {} size_t getNormalIndex() const {return fi ? _index / S : _index;} size_t _index; }; void print(std::ostream& out) const; void clear(); size_t getMemoryUse() const; /// Asserts internal invariants if asserts are turned on. bool isValid() const; private: ComTree& operator=(const ComTree& tree) const; // not available Entry* _array; /// Macaulay 2 uses Mathic and Macaulay 2 also uses the Boehm garbage /// collector. Since _array points to a place before the array we /// are using, that array will be garbage collected if we do not /// keep around a second pointer that does point into the array. /// That is the purpose of _arrayKeepAlive. Entry* _arrayKeepAlive; Node _lastLeaf; Node _capacityEnd; }; template void ComTree::clear() { _lastLeaf = Node(0); } template size_t ComTree::getMemoryUse() const { return capacity() * sizeof(E); } template std::ostream& operator<<(std::ostream& out, const ComTree& tree) { tree.print(out); return out; } template ComTree::ComTree(size_t initialCapacity): _array(static_cast(0) - 1), _arrayKeepAlive(0), _lastLeaf(0), _capacityEnd(Node(0).next(initialCapacity)) { if (initialCapacity > 0) { _arrayKeepAlive = new E[initialCapacity]; _array = _arrayKeepAlive - 1; } MATHIC_ASSERT(isValid()); } template ComTree::ComTree(const ComTree& tree, size_t minCapacity): _array(static_cast(0) - 1), _arrayKeepAlive(0), _lastLeaf(tree._lastLeaf) { if (tree.size() > minCapacity) minCapacity = tree.size(); _capacityEnd = Node(0).next(minCapacity); if (minCapacity != 0) { _arrayKeepAlive = new E[minCapacity]; _array = _arrayKeepAlive - 1; for (Node i; i <= tree.lastLeaf(); ++i) (*this)[i] = tree[i]; } MATHIC_ASSERT(isValid()); } template ComTree::ComTree(ComTree&& tree): _array(tree._array), _arrayKeepAlive(tree._arrayKeepAlive), _lastLeaf(tree._lastLeaf), _capacityEnd(tree._capacityEnd) { tree._array = static_cast(0) - 1; tree._arrayKeepAlive = 0; _lastLeaf = Node(0); _capacityEnd = Node(0); } template inline E& ComTree::operator[](Node n) { MATHIC_ASSERT(_array == _arrayKeepAlive - 1); if (!FI) return _array[n._index]; char* base = reinterpret_cast(_array); E* element = reinterpret_cast(base + n._index); MATHIC_ASSERT(element == &(_array[n._index / sizeof(E)])); return *element; } template inline const E& ComTree::operator[](Node n) const { return const_cast*>(this)->operator[](n); } template void ComTree::pushBack(const E& value) { if (_lastLeaf == _capacityEnd) increaseCapacity(); _lastLeaf = _lastLeaf.next(); (*this)[lastLeaf()] = value; } template void ComTree::pushBackWithCapacity(const E& value) { MATHIC_ASSERT(_lastLeaf != _capacityEnd); _lastLeaf = _lastLeaf.next(); (*this)[lastLeaf()] = value; } template void ComTree::popBack() { MATHIC_ASSERT(_lastLeaf >= Node()); _lastLeaf = _lastLeaf.prev(); } template void ComTree::swap(ComTree& tree) { MATHIC_ASSERT(isValid()); MATHIC_ASSERT(tree.isValid()); std::swap(_array, tree._array); std::swap(_arrayKeepAlive, tree._arrayKeepAlive); std::swap(_lastLeaf, tree._lastLeaf); std::swap(_capacityEnd, tree._capacityEnd); MATHIC_ASSERT(isValid()); MATHIC_ASSERT(tree.isValid()); } template typename ComTree::Node ComTree::Node::parent() const { return fi ? Node((_index / (2 * S)) * S) : Node(_index / 2); } template typename ComTree::Node ComTree::Node::left() const { return Node(2 * _index); } template typename ComTree::Node ComTree::Node::right() const { return fi ? Node(2 * _index + S) : Node(2 * _index + 1); } template typename ComTree::Node ComTree::Node::sibling() const { return fi ? Node(_index ^ S) : Node(_index ^ 1); } template typename ComTree::Node ComTree::Node::leftSibling() const { return fi ? Node(_index & ~S) : Node(_index & ~1); } template typename ComTree::Node ComTree::Node::next() const { return fi ? Node(_index + S) : Node(_index + 1); } template typename ComTree::Node ComTree::Node::next(size_t count) const { return fi ? Node(_index + S * count) : Node(_index + count); } template typename ComTree::Node ComTree::Node::prev() const { return fi ? Node(_index - S) : Node(_index - 1); } template void ComTree::print(std::ostream& out) const { Node last = lastLeaf(); for (Node i; i <= last; i = i.next()) { if ((i._index & (i._index - 1)) == 0) // if i._index is a power of 2 out << "\n " << i._index << ':'; out << ' ' << (*this)[i]; } out << "}\n"; } template bool ComTree::isValid() const { #ifndef MATHIC_DEBUG return true; #else MATHIC_ASSERT(_array == _arrayKeepAlive - 1); // sizeof(Entry) must be a power of two if FastIndex is true. MATHIC_ASSERT(!FI || (sizeof(E) & (sizeof(E) - 1)) == 0); if (capacity() == 0) { MATHIC_ASSERT(_array == static_cast(0) - 1); MATHIC_ASSERT(_capacityEnd == Node(0)); MATHIC_ASSERT(_lastLeaf == Node(0)); } else { MATHIC_ASSERT(_array != static_cast(0) - 1); MATHIC_ASSERT(_capacityEnd > Node(0)); MATHIC_ASSERT(_lastLeaf <= _capacityEnd); } return true; #endif } template bool ComTree::hasFreeCapacity(size_t extraCapacity) const { return Node(_capacityEnd._index - _lastLeaf._index) >= Node(0).next(extraCapacity); } template void ComTree::increaseCapacity() { MATHIC_ASSERT(isValid()); ComTree newTree(capacity() == 0 ? 16 : capacity() * 2); for (Node i; i <= lastLeaf(); i = i.next()) newTree.pushBack((*this)[i]); MATHIC_ASSERT(newTree.isValid()); std::swap(_array, newTree._array); std::swap(_arrayKeepAlive, newTree._arrayKeepAlive); std::swap(_capacityEnd, newTree._capacityEnd); MATHIC_ASSERT(isValid()); } } #endif mathic-master/src/mathic/Comparer.h000066400000000000000000000005351311555225300175760ustar00rootroot00000000000000#ifndef MATHIC_COMPARER_GUARD #define MATHIC_COMPARER_GUARD namespace mathic { template class Comparer { public: Comparer(const C& conf): _conf(conf) {} template bool operator()(const A& a, const B& b) const { return _conf.isLessThan(a.get(), b.get()); } private: const C& _conf; }; } #endif mathic-master/src/mathic/DivFinder.h000077500000000000000000000055361311555225300177110ustar00rootroot00000000000000#ifndef MATHIC_DIV_FINDER_GUARD #define MATHIC_DIV_FINDER_GUARD /** An object that supports queries for divisors of a monomial. This is an object for documentation purposes. Use the concrete implementations of this interface to get an actual DivFinder-like object. DivFinder stores configurable Entry objects that represent a monomial together with any required additional information. The class is parameterized on a Configuration. The Configuration class must have the following members. * A type Monomial Represents a monomial. * A type Entry These are the things added to the finder. Entry represents a monomial along with any additional required information that client code needs to associate with monomials in the finder. * A type Exponent These are exponents of the monomials. Exponent must have a copy constructor, an operator= and an operator< for comparision with other exponents. * A function Exponent getExponent(Monomial m, size_t var) const Returns the exponent of the variable var in m. m can be a const reference. * A function bool divides(Entry a, Monomial b) const * A function bool divides(Monomial a, Entry b) const * A function bool divides(Entry a, Entry b) const Returns whether a divides b. a and b can be const references. If Entry and Monomial are the same type then only one function is needed. * A function size_t getVarCount() const Returns the number of variables. Variables are indexed from 0 to getVarCount() - 1. Must be a positive number. * static const bool UseDivMask Set to true to use div masks to speed up queries. This must be a static const data member. * size_t getUseAutomaticRebuild() const * double getRebuildRatio() const * size_t getRebuildMin() const If getUseAutomaticRebuild() returns true, the tree will call rebuild after a total of max(size() * getRebuildRatio(), getRebuildMin()) entry insertions and removals have occurred. A rebuild ratio of 0.5 and a minimum of 500 has worked well for random vectors. * A method bool isLessThan(Entry a, Monomial b) const * A method bool isLessThan(Monomial a, Entry b) const * A method bool isLessThan(Entry a, Entry b) const isLessThan must define a total order < on entries/monomials. a and b can be const references. If Entry and Monomial are the same type then only one function is needed. It is possible to obtain non-const Entries from a DivFinder. It is allowed to change these, but the monomial they represent must not change. When the DivFinder calls some method X on the Configuration, the Configuration must not in return cause a method to be called on the DivFinder until the method X has returned. This is because the DivFinder may not be in a valid state at the time it is calling X. @todo: put these docs somewhere else. */ namespace { template class DivFinder; // no implementation } #endif mathic-master/src/mathic/DivList.h000077500000000000000000000454211311555225300174120ustar00rootroot00000000000000#ifndef MATHIC_DIV_ARRAY_GUARD #define MATHIC_DIV_ARRAY_GUARD #include "stdinc.h" #include "DivMask.h" #include "Comparer.h" #include #include #include #include #include #include namespace mathic { /** An object that supports queries for divisors of a monomial using an array of monomials. See DivFinder for more documentation. Extra fields for Configuration: * static const bool UseLinkedList Use a linked list if true, otherwise use an array. * static const bool UseDivMask Use div masks if true. * bool getSortOnInsert() const Keep the monomials sorted to speed up queries. */ template class DivList; namespace DivListHelper { // Implementation details for DivList. template struct ListImpl; template struct ListImpl { typedef std::vector Impl; }; template struct ListImpl { typedef std::list Impl; }; } template class DivList { public: typedef C Configuration; typedef typename C::Entry Entry; typedef typename C::Monomial Monomial; typedef typename C::Exponent Exponent; static const bool UseLinkedList = C::UseLinkedList; static const bool UseDivMask = C::UseDivMask; private: typedef typename DivMask::Extender ExtEntry; typedef typename DivMask::Extender ExtMonoRef; typedef typename DivMask::Calculator DivMaskCalculator; typedef typename DivListHelper::ListImpl::Impl List; typedef typename List::iterator ListIter; typedef typename List::const_iterator CListIter; public: class iterator; class const_iterator; DivList(const C& configuration); template void insert(Iter begin, Iter end); void insert(const Entry& entry); bool removeMultiples(const Monomial& monomial); template bool removeMultiples (const Monomial& monomial, MultipleOutput& out); bool removeElement(const Monomial& monomial); iterator findDivisorIterator(const Monomial& monomial); Entry* findDivisor(const Monomial& monomial); const Entry* findDivisor(const Monomial& monomial) const; template void findAllDivisors(const Monomial& monomial, DO& out); template void findAllDivisors(const Monomial& monomial, DO& out) const; template void findAllMultiples(const Monomial& monomial, DO& out); template void findAllMultiples(const Monomial& monomial, Output& output) const { ConstEntryOutput constOutput(output); const_cast&>(*this).findAllMultiples(monomial, constOutput); } template void forAll(EntryOutput& output); template void forAll(EntryOutput& output) const; iterator begin() {return iterator(_list.begin());} const_iterator begin() const {return const_iterator(_list.begin());} iterator end() {return iterator(_list.end());} const_iterator end() const {return const_iterator(_list.end());} bool empty() const {return _list.empty();} size_t size() const {return _list.size();} std::string getName() const; C& getConfiguration() {return _conf;} const C& getConfiguration() const {return _conf;} void moveToFront(iterator pos); void rebuild(); /** Returns the number of bytes allocated by this object. Does not include sizeof(*this), does not include any additional memory that the configuration may have allocated and does not include any memory that an Entry may point to. Does include sizeof(Entry) as well as unused memory that is being kept to avoid frequent allocations. */ size_t getMemoryUse() const; private: DivList(const DivList&); // unavailable void operator=(const DivList&); // unavailable void resetNumberOfChangesTillRebuild(); void reportChanges(size_t changesMadeCount); template class ConstEntryOutput { public: ConstEntryOutput(DO& out): _out(out) {} bool proceed(const Entry& entry) {return _out.proceed(entry);} private: DO& _out; }; class DummyMultipleOutput { public: void push_back(Entry& e) {} }; List _list; C _conf; DivMaskCalculator _divMaskCalculator; size_t _changesTillRebuild; /// Update using reportChanges(). }; template class DivList::iterator : public std::iterator { public: friend class DivList; explicit iterator(ListIter it): _it(it) {} operator const_iterator() const {return const_iterator(_it);} bool operator==(iterator it) {return _it == it._it;} bool operator!=(iterator it) {return _it != it._it;} bool operator==(const_iterator it); // {return it == const_iterator(*this);} bool operator!=(const_iterator it); // {return it != const_iterator(*this);} iterator& operator++() {++_it; return *this;} iterator operator++(int) {iterator tmp = *this; operator++(); return tmp;} iterator& operator--() {--_it; return *this;} iterator operator--(int) {iterator tmp = *this; operator--(); return tmp;} Entry& operator*() const {return _it->get();} Entry* operator->() const {return &_it->get();} protected: ListIter getInternal() {return _it;} private: ListIter _it; }; template class DivList::const_iterator : public std::iterator { public: friend class DivList; explicit const_iterator(CListIter it): _it(it) {} bool operator==(const_iterator it) {return _it == it._it;} bool operator!=(const_iterator it) {return _it != it._it;} bool operator==(iterator it) {return *this == const_iterator(it);} bool operator!=(iterator it) {return *this != const_iterator(it);} const Entry& operator*() const {return _it->get();} const Entry* operator->() const {return &_it->get();} const_iterator& operator++() {++_it; return *this;} const_iterator operator++(int) { const_iterator tmp = *this; operator++(); return tmp; } const_iterator& operator--() {--_it; return *this;} const_iterator operator--(int) { const_iterator tmp = *this; operator--(); return tmp; } protected: ListIter getInternal() {return _it;} private: CListIter _it; }; template bool DivList::iterator::operator==(const_iterator it) {return it == const_iterator(*this);} template bool DivList::iterator::operator!=(const_iterator it) {return it != const_iterator(*this);} namespace DivListHelper { template size_t removeMultiples (C& conf, std::vector& list, const M& monomial, MO& out) { typedef typename std::vector::iterator iterator; iterator it = list.begin(); iterator oldEnd = list.end(); for (; it != oldEnd; ++it) { if (monomial.divides(*it, conf)) { out.push_back(it->get()); break; } } if (it == oldEnd) return 0; iterator newEnd = it; for (++it; it != oldEnd; ++it) { if (!monomial.divides(*it, conf)) { *newEnd = *it; ++newEnd; } else out.push_back(it->get()); } const size_t origSize = list.size(); const size_t newSize = std::distance(list.begin(), newEnd); MATHIC_ASSERT(newSize < list.size()); list.resize(newSize); return origSize - newSize; } template size_t removeMultiples(C& conf, std::list& list, const M& monomial, MO& out) { #ifdef MATHIC_DEBUG const size_t origSize = list.size(); #endif typedef typename std::list::iterator iterator; iterator it = list.begin(); iterator oldEnd = list.end(); size_t removedCount = 0; while (it != oldEnd) { if (monomial.divides(*it, conf)) { out.push_back(it->get()); ++removedCount; it = list.erase(it); } else ++it; } MATHIC_ASSERT(list.size() + removedCount == origSize); return removedCount; } template void moveToFront(std::vector& list, It pos) { E valueToMove = *pos; It begin = list.begin(); while (pos != begin) { It prev = pos; --pos; *prev = *pos; } list.front() = valueToMove; } template void moveToFront(std::list& list, It pos) { list.splice(list.begin(), list, pos); } template typename std::list::iterator insertSort(C& conf, std::list& list, const E& entry) { typedef typename std::list::iterator iterator; iterator end = list.end(); iterator it = list.begin(); for (; it != end; ++it) if (conf.isLessThan(entry.get(), it->get())) break; return list.insert(it, entry); } template typename std::vector::iterator insertSort(C& conf, std::vector& list, const E& entry) { typedef typename std::vector::iterator iterator; iterator it = std::upper_bound(list.begin(), list.end(), entry, Comparer(conf)); return list.insert(it, entry); } template void sortAll(C& conf, std::list& list) { list.sort(Comparer(conf)); } template void sortAll(C& conf, std::vector& list) { std::sort(list.begin(), list.end(), Comparer(conf)); } template typename std::vector::iterator findDivisorSorted(C& conf, std::vector& list, const M& monomial) { typedef typename std::vector::iterator iterator; iterator rangeEnd = std::upper_bound(list.begin(), list.end(), monomial, Comparer(conf)); iterator it = list.begin(); for (; it != rangeEnd; ++it) if (it->divides(monomial, conf)) return it; return list.end(); } template typename std::list::iterator findDivisorSorted(C& conf, std::list& list, const M& monomial) { typedef typename std::list::iterator iterator; iterator end = list.end(); iterator it = list.begin(); size_t count = 0; for (; it != end; ++it) { ++count; if (count == 35) { count = 0; if (conf.isLessThan(monomial.get(), it->get())) break; } if (it->divides(monomial, conf)) return it; } return end; } template void findAllDivisorsSorted (C& conf, std::vector& list, const M& monomial, DO& out) { typedef typename std::vector::iterator iterator; iterator rangeEnd = std::upper_bound(list.begin(), list.end(), monomial, Comparer(conf)); iterator it = list.begin(); for (; it != rangeEnd; ++it) if (it->divides(monomial, conf)) if (!out.proceed(it->get())) break; } template void findAllDivisorsSorted (C& conf, std::list& list, const M& monomial, O& out) { typedef typename std::list::iterator iterator; iterator end = list.end(); iterator it = list.begin(); size_t count = 0; for (; it != end; ++it) { ++count; if (count == 35) { count = 0; if (conf.isLessThan(monomial.get(), it->get())) break; } if (it->divides(monomial, conf)) if (!out.proceed(it->get())) break; } } } template DivList::DivList(const C& configuration): _conf(configuration), _divMaskCalculator(configuration) { resetNumberOfChangesTillRebuild(); } template void DivList::insert(const Entry& entry) { ExtEntry extEntry(entry, _divMaskCalculator, _conf); if (!_conf.getSortOnInsert()) _list.push_back(extEntry); else DivListHelper::insertSort(_conf, _list, extEntry); reportChanges(1); } template template void DivList::insert(Iter rangeBegin, Iter rangeEnd) { if (!empty()) { for (; rangeBegin != rangeEnd; ++rangeBegin) insert(*rangeBegin); return; } if (rangeBegin == rangeEnd) return; _divMaskCalculator.rebuild(rangeBegin, rangeEnd, _conf); for (; rangeBegin != rangeEnd; ++rangeBegin) _list.push_back(ExtEntry(*rangeBegin, _divMaskCalculator, _conf)); if (_conf.getSortOnInsert()) DivListHelper::sortAll(_conf, _list); resetNumberOfChangesTillRebuild(); } template template bool DivList::removeMultiples(const Monomial& monomial, MO& out) { ExtMonoRef extMonomial(monomial, _divMaskCalculator, _conf); #ifdef MATHIC_DEBUG const size_t origSize = size(); #endif const size_t removedCount = DivListHelper::removeMultiples(_conf, _list, extMonomial, out); MATHIC_ASSERT_NO_ASSUME(size() + removedCount == origSize); reportChanges(removedCount); return removedCount > 0; } template bool DivList::removeMultiples(const Monomial& monomial) { DummyMultipleOutput out; return removeMultiples(monomial, out); } template bool DivList::removeElement(const Monomial& monomial) { const size_t varCount = _conf.getVarCount(); for (ListIter it = _list.begin(); it != _list.end(); ++it) { for (size_t var = 0; var < varCount; ++var) { if (_conf.getExponent(monomial, var) != _conf.getExponent(it->get(), var)) { goto skip; } } _list.erase(it); return true; skip:; } return false; } template typename DivList::iterator DivList::findDivisorIterator(const Monomial& monomial) { ExtMonoRef extMonomial(monomial, _divMaskCalculator, _conf); if (!_conf.getSortOnInsert()) { ListIter listEnd = _list.end(); for (ListIter it = _list.begin(); it != listEnd; ++it) { if (it->divides(extMonomial, _conf)) return iterator(it); } return iterator(listEnd); } else return iterator(DivListHelper::findDivisorSorted(_conf, _list, extMonomial)); } template typename DivList::Entry* DivList::findDivisor(const Monomial& monomial) { ExtMonoRef extMonomial(monomial, _divMaskCalculator, _conf); if (!_conf.getSortOnInsert()) { const ListIter listEnd = _list.end(); for (ListIter it = _list.begin(); it != listEnd; ++it) { if (it->divides(extMonomial, _conf)) return &it->get(); } return 0; } else { ListIter it = DivListHelper::findDivisorSorted(_conf, _list, extMonomial); return it == _list.end() ? 0 : &it->get(); } } template const typename DivList::Entry* DivList::findDivisor(const Monomial& monomial) const { return const_cast&>(*this).findDivisor(monomial); } template template void DivList::findAllDivisors(const Monomial& monomial, DO& out) { ExtMonoRef extMonomial(monomial, _divMaskCalculator, _conf); if (!_conf.getSortOnInsert()) { const ListIter listEnd = _list.end(); for (ListIter it = _list.begin(); it != listEnd; ++it) if (it->divides(extMonomial, _conf)) if (!out.proceed(it->get())) break; } else DivListHelper::findAllDivisorsSorted(_conf, _list, extMonomial, out); } template template void DivList::findAllMultiples(const Monomial& monomial, DO& out) { // todo: consider doing sorted version ExtMonoRef extMonomial(monomial, _divMaskCalculator, _conf); const ListIter listEnd = _list.end(); for (ListIter it = _list.begin(); it != listEnd; ++it) if (extMonomial.divides(*it, _conf)) if (!out.proceed(it->get())) break; } template template void DivList::findAllDivisors(const Monomial& monomial, DO& output) const { ConstEntryOutput constOutput(output); const_cast&>(*this).findAllDivisors(monomial, constOutput); } template template void DivList::forAll(EntryOutput& output) { iterator stop = end(); for (iterator it = begin(); it != stop; ++it) if (!output.proceed(*it)) return; } template template void DivList::forAll(EntryOutput& output) const { ConstEntryOutput constOutput(output); const_cast&>(*this).forAll(constOutput); } template std::string DivList::getName() const { std::ostringstream out; out <<"DivList" << (UseLinkedList ? " linked" : " array"); if (UseDivMask && _conf.getDoAutomaticRebuilds()) { out << " autob:" << _conf.getRebuildRatio() << '/' << _conf.getRebuildMin(); } out << (_conf.getSortOnInsert() ? " sort" : "") << (UseDivMask ? " dmask" : ""); return out.str(); } template void DivList::moveToFront(iterator pos) { DivListHelper::moveToFront(_list, pos.getInternal()); } template void DivList::rebuild() { const size_t totalSize = size(); typedef memt::ArenaVector TmpContainer; TmpContainer tmpCopy(memt::Arena::getArena(), totalSize); std::copy(begin(), end(), std::back_inserter(tmpCopy)); _divMaskCalculator.rebuild(tmpCopy.begin(), tmpCopy.end(), _conf); ListIter listEnd = _list.end(); for (ListIter it = _list.begin(); it != listEnd; ++it) it->recalculateDivMask(_divMaskCalculator, _conf); resetNumberOfChangesTillRebuild(); } template void DivList::resetNumberOfChangesTillRebuild() { if (!_conf.getDoAutomaticRebuilds()) return; MATHIC_ASSERT(_conf.getRebuildRatio() > 0); _changesTillRebuild = std::max (static_cast(size() * _conf.getRebuildRatio()), _conf.getRebuildMin()); } template void DivList::reportChanges(size_t changesMadeCount) { // note how negative value/overflow of _changesTillRebuild cannot // happen this way. if (!_conf.getDoAutomaticRebuilds()) return; if (_changesTillRebuild > changesMadeCount) _changesTillRebuild -= changesMadeCount; else rebuild(); } template size_t DivList::getMemoryUse() const { return _list.capacity() * sizeof(_list.front()); } } #endif mathic-master/src/mathic/DivMask.cpp000066400000000000000000000007361311555225300177220ustar00rootroot00000000000000#include "DivMask.h" #ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO namespace mathic { namespace DivMaskStats { unsigned long maskComputes = 0; unsigned long maskChecks = 0; unsigned long maskHits = 0; unsigned long divChecks = 0; unsigned long divDivides = 0; unsigned long divHits = 0; } } #else // The purpose of dummy is to silence a MSVC linker warning // that says that this file is not adding anything to the build. namespace {void dummy(){}} #endif mathic-master/src/mathic/DivMask.h000066400000000000000000000357741311555225300174010ustar00rootroot00000000000000#ifndef MATHIC_BIT_MASK_GUARD #define MATHIC_BIT_MASK_GUARD #include "stdinc.h" #include #include #include // Value x means do 2^x mask checks before printing stats //#define MATHIC_TRACK_DIV_MASK_HIT_RATIO 25 //#define MATHIC_TRACK_DIV_MASK_HIT_RATIO 30 #ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO #include #include "ColumnPrinter.h" #endif namespace mathic { #ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO namespace DivMaskStats { extern unsigned long maskComputes; // div masks computed extern unsigned long maskChecks; // how many times mask is checked extern unsigned long maskHits; // times canDivide returns false extern unsigned long divChecks; // times divisibility is checked with mask extern unsigned long divDivides; // mask can't hit as there is divisibility extern unsigned long divHits; // times mask rules out divisibility } #endif /** Class representing a div mask. This is a set of bits that can be used to determine that one monomial cannot divide another monomial. */ class DivMask { public: /** Calculates div masks. Don't change NullCalculator from its default value. The actual code are in partial specializations selecting the right version based on NullCalculator. */ template class Calculator; DivMask(): _mask(0) {} static DivMask getMaxMask() {return ~static_cast(0);} template DivMask(const T& t, const Calculator& calc, const Configuration& conf): _mask(calc.compute(t, conf)) {} template void recalculate(const T& t, const Calculator& calc, const Configuration& conf) { _mask = calc.compute(t, conf); } bool canDivide(const DivMask& mask) const { const bool canDiv = ((_mask & ~mask._mask) == 0); #ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO ++DivMaskStats::maskChecks; if (!canDiv) ++DivMaskStats::maskHits; // print stats every 2^MATHIC_TRACK_DIV_MASK_HIT_RATIO time const unsigned long mod = (1 << MATHIC_TRACK_DIV_MASK_HIT_RATIO) - 1; if ((DivMaskStats::maskChecks & mod) == 0) { std::cerr << "**** DivMask stats (turn off by not defining macro) ****\n"; ColumnPrinter pr; pr.addColumn(true, "* "); pr.addColumn(false, " "); pr.addColumn(false, " "); pr.addColumn(true, " "); pr[0] << "masks computed:\n"; pr[1] << ColumnPrinter::commafy(DivMaskStats::maskComputes) << '\n'; pr[2] << ColumnPrinter::percent (DivMaskStats::maskComputes, DivMaskStats::maskChecks) << '\n'; pr[3] << "of mask checks\n"; pr[0] << "mask checks:\n"; pr[1] << ColumnPrinter::commafy(DivMaskStats::maskChecks) << '\n'; pr[2] << '\n'; pr[3] << '\n'; pr[0] << "mask hits:\n"; pr[1] << ColumnPrinter::commafy(DivMaskStats::maskHits) << '\n'; pr[2] << ColumnPrinter::percent (DivMaskStats::maskHits, DivMaskStats::maskChecks) << '\n'; pr[3] << "of mask checks\n"; pr[0] << "mask div checks:\n"; pr[1] << ColumnPrinter::commafy(DivMaskStats::divChecks) << '\n'; pr[2] << ColumnPrinter::percent (DivMaskStats::divChecks, DivMaskStats::maskChecks) << '\n'; pr[3] << "of mask checks\n"; pr[0] << "actually divide:\n"; pr[1] << ColumnPrinter::commafy(DivMaskStats::divDivides) << '\n'; pr[2] << ColumnPrinter::percent (DivMaskStats::divDivides, DivMaskStats::divChecks) << '\n'; pr[3] << "of div checks\n"; pr[0] << "mask div hits:\n"; pr[1] << ColumnPrinter::commafy(DivMaskStats::divHits) << '\n'; pr[2] << ColumnPrinter::percent (DivMaskStats::divHits, DivMaskStats::divChecks) << '\n'; pr[3] << "of div checks, " << ColumnPrinter::percent (DivMaskStats::divHits, DivMaskStats::divChecks - DivMaskStats::divDivides) << " adjusted.\n"; std::cerr << pr << "****\n"; } #endif return canDiv; } void combineAnd(const DivMask& mask) {_mask &= mask._mask;} bool operator==(DivMask& mask) const {return _mask == mask._mask;} bool operator!=(DivMask& mask) const {return _mask != mask._mask;} /** Extender extends T with a div mask if UseDivMask is true. It is allowed for T to be a reference type or const. */ template class Extender; /** Base class to include a DivMask into a class at compile time based on the template parameter UseDivMask. The class offers the same methods either way, but they are replaced by do-nothing or asserting versions if UseDivMask is false. */ template class HasDivMask; protected: template class ExponentComparer { public: ExponentComparer(size_t var, const C& conf): _var(var), _conf(conf) {} template bool operator()(const E& a, const E& b) const { return _conf.getExponent(a, _var) < _conf.getExponent(b, _var); } private: size_t _var; const C& _conf; }; struct VarData { size_t var; // the variable in question // let e be the average of the minimum and maximum exponent of var. // then split is the number of elements whose exponent of var is // <= average, or it is the number of elements whose exponent of var // is > average, whichever is those two numbers is smaller. size_t split; // How many bits of the DivMask to dedicate to this variable. size_t bitsForVar; bool operator<(const VarData& data) const { return split > data.split; // larger split first in order } }; typedef unsigned int MaskType; DivMask(MaskType mask): _mask(mask) {} private: /** To eliminate warnings about T& if T is already a reference type. */ template struct Ref {typedef T& RefType;}; template struct Ref {typedef T& RefType;}; MaskType _mask; }; template class DivMask::Calculator { public: Calculator(const C& conf) {rebuildDefault(conf);} /** Change the meaning of the bits in the div masks produced by this object to something that will likely work well for entries in [begin, end). All div masks will have to be recomputed after this. Mixing div masks computed before a call to rebuild() with ones after has unpredictable results. */ template void rebuild(Iter begin, Iter end, const C& conf); /** Rebuilds without the benefit of knowing a range of entries that the div masks are supposed to work well for. */ void rebuildDefault(const C& conf); /** Computes a div mask for t. */ template DivMask::MaskType compute(const T& t, const C& conf) const; private: typedef typename C::Exponent Exponent; /** If entry at index i is the pair (var,exp) then the bit at index var in a bit mask is 1 if the exponent of var in the monomial is strictly greater than exp. */ typedef std::vector > BitContainer; BitContainer _bits; }; template template void DivMask::Calculator:: rebuild(Iter begin, Iter end, const C& conf) { const size_t size = std::distance(begin, end); if (size == 0) { rebuildDefault(conf); return; } _bits.clear(); const size_t varCount = conf.getVarCount(); const size_t TotalBits = sizeof(MaskType) * BitsPerByte; // ** Determine information about each variable std::vector datas; for (size_t var = 0; var < varCount; ++var) { Exponent min = conf.getExponent(*begin, 0); Exponent max = min; for (Iter it = begin; it != end; ++it) { Exponent exp = conf.getExponent(*it, var); if (max < exp) max = exp; if (exp < min) min = exp; } Exponent average = min + (max - min) / 2; // this formula avoids overflow size_t split = 0; for (Iter it = begin; it != end; ++it) if (conf.getExponent(*it, var) < average) ++split; if (split > size / 2) split = size - split; VarData data; data.var = var; data.split = split; datas.push_back(data); } std::sort(datas.begin(), datas.end()); MATHIC_ASSERT(datas.size() == varCount); // distribute bits to variables according to the data collected std::vector bitsForVars(varCount); for (size_t i = 0; i < varCount; ++i) { const size_t var = datas[i].var; bitsForVars[var] = TotalBits / varCount; if (i < TotalBits % varCount) ++bitsForVars[var]; } // calculate the meaning of each bit and put it in _bits for (size_t var = 0; var < varCount; ++var) { const size_t bitsForVar = bitsForVars[var]; if (bitsForVar == 0) continue; const bool useRank = false; if (useRank) { std::sort(begin, end, ExponentComparer(var, conf)); size_t size = std::distance(begin, end); size_t offset = size / (bitsForVar + 1); if (offset== 0) offset = 1; Exponent lastExp; size_t lastJ = 0; for (size_t i = 1; i <= bitsForVar; ++i) { size_t j = i * offset; if (i > 1 && j < lastJ) j = lastJ + 1; if (j >= size) j = size - 1; if (i > 1) { while (j < size && conf.getExponent(begin[j], var) == lastExp) ++j; if (j == size) break; } _bits.push_back( std::make_pair(var, conf.getExponent(begin[j], var))); lastJ = j; lastExp = conf.getExponent(begin[j], var); if (j == size - 1) break; } } else { Exponent min = conf.getExponent(*begin, 0); Exponent max = min; for (Iter it = begin; it != end; ++it) { Exponent exp = conf.getExponent(*it, var); if (max < exp) max = exp; if (exp < min) min = exp; } // divide the range [a,b] into bitsForVar equal pieces // and use the left end points of those ranges // as the points for the bits. Exponent increment = (max - min) / static_cast(bitsForVar); // todo: can avoid cast? if (increment == 0) increment = 1; for (size_t i = 0; i < bitsForVar; ++i) _bits.push_back(std::make_pair(var, min + increment * static_cast(i))); // todo: can avoid cast? } } } template void DivMask::Calculator:: rebuildDefault(const C& conf) { _bits.clear(); const size_t varCount = conf.getVarCount(); const size_t TotalBits = sizeof(MaskType) * BitsPerByte; for (size_t var = 0; var < varCount; ++var) { const size_t bitsForVar = TotalBits / varCount + (var < TotalBits % varCount); Exponent exp = 0; for (size_t i = 0; i < bitsForVar; ++i) { _bits.push_back(std::make_pair(var, exp)); exp = (i == 0 ? 1 : exp * 2); } } } template template DivMask::MaskType DivMask::Calculator:: compute(const T& t, const C& conf) const { #ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO ++DivMaskStats::maskComputes; #endif typedef typename BitContainer::const_iterator const_iterator; const const_iterator end = _bits.end(); DivMask::MaskType mask = 0; for (const_iterator it = _bits.begin(); it != end; ++it) mask = (mask << 1) | (conf.getExponent(t, it->first) > it->second); return mask; } template class DivMask::Calculator { public: Calculator(const C& conf) {} template void rebuild(Iter begin, Iter end, const C& conf) {} void rebuildDefault(const C& conf) {} }; template<> class DivMask::HasDivMask { public: template HasDivMask(const T& t, const Calculator& calc, const C& conf): _mask(t, calc, conf) {} HasDivMask() {resetDivMask();} DivMask& getDivMask() {return _mask;} const DivMask& getDivMask() const {return _mask;} void resetDivMask() {_mask = DivMask::getMaxMask();} bool canDivide(const HasDivMask& t) const { return getDivMask().canDivide(t.getDivMask()); } void updateToLowerBound(const HasDivMask& t) { _mask.combineAnd(t.getDivMask()); } protected: template void recalculateDivMask (const T& t, const Calculator& calc, const C& conf) { _mask.recalculate(t, calc, conf); } private: DivMask _mask; }; template<> class DivMask::HasDivMask { public: void resetDivMask() {MATHIC_ASSERT(false);} DivMask getDivMask() const {MATHIC_ASSERT(false); return DivMask();} bool canDivide(const HasDivMask& t) const {return true;} template void updateToLowerBound(const HasDivMask& entry) {} }; template class DivMask::Extender : public HasDivMask { private: typedef typename Ref::RefType Reference; typedef typename Ref::RefType ConstReference; public: Extender(): HasDivMask(), _t() {} template Extender(ConstReference t, const Calculator& calc, const C& conf): HasDivMask(t, calc, conf), _t(t) {} template bool divides(const Extender& t, const C& conf) const { bool canDiv = this->canDivide(t); #ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO ++DivMaskStats::divChecks; if (!canDiv) ++DivMaskStats::divHits; #endif if (!canDiv) return false; bool actuallyDivides = conf.divides(get(), t.get()); #ifdef MATHIC_TRACK_DIV_MASK_HIT_RATIO if (actuallyDivides) ++DivMaskStats::divDivides; #endif return actuallyDivides; } template void recalculateDivMask(const Calculator& calc, const C& conf) { this->HasDivMask::recalculateDivMask(get(), calc, conf); } Reference get() {return _t;} ConstReference get() const {return _t;} private: T _t; }; template class DivMask::Extender : public HasDivMask { private: typedef typename Ref::RefType Reference; typedef typename Ref::RefType ConstReference; public: Extender(): HasDivMask(), _t() {} template Extender(ConstReference t, const Calculator& calc, const C& conf): HasDivMask(), _t(t) {} template bool divides(const Extender& t, const C& conf) const { return conf.divides(get(), t.get()); } template void recalculateDivMask(const Calculator& calc, const C& conf) {} Reference get() {return _t;} ConstReference get() const {return _t;} private: T _t; }; } #endif mathic-master/src/mathic/GeoFront.h000077500000000000000000000257571311555225300175710ustar00rootroot00000000000000#ifndef MATHIC_GEO_FRONT_GUARD #define MATHIC_GEO_FRONT_GUARD #include "stdinc.h" #include #include namespace mathic { /** To be used by Geobucket class. Configuration is the Configuration from the owning Geobucket. Bucket is the Bucket class from the owning Geobucket. Having Bucket be a parameter allows it to be used before it is declared so that this header need not include Geobucket's header, which would otherwise be a cyclic dependency. This also grants access to Geobucket::Bucket which is otherwise private. Why not make this an inner template class of Geobucket? Because inner template classes cannot be specialized without also specializing the outer class. */ template class Geobucket; template::Bucket, bool Order = Configuration::trackFront> class GeoFront; // ******************************************************************** // GeoFront maintaining no special order template class GeoFront { public: /** A reference is kept to entryCountRef so that it can be updated in the event of a deduplication. */ GeoFront(const C& conf, size_t& entryCountRef): _cachedMaxBucket(0), _entryCountRef(&entryCountRef), _conf(conf) { MATHIC_ASSERT(!C::trackFront); } void clear() { _cachedMaxBucket = 0; } void reserveCapacity(size_t newCapacity) {} void bucketsInvalidated(Bucket* oldBegin, Bucket* newBegin) { _cachedMaxBucket = 0; } bool empty() const {return *_entryCountRef == 0;} void insert(Bucket* bucket) {_cachedMaxBucket = 0;} void remove(Bucket* bucket) {_cachedMaxBucket = 0;} void keyIncreased(Bucket* bucket) {_cachedMaxBucket = 0;} void keyDecreased(Bucket* bucket) {_cachedMaxBucket = 0;} void swapKeys(Bucket* a, Bucket* b) {} bool larger(const Bucket* a, const Bucket* b) const { MATHIC_ASSERT(false); return false; } const Bucket* getMax(Bucket* bucketBegin, Bucket* bucketEnd) const; #ifdef MATHIC_DEBUG bool debugIsValid(Bucket* bucketBegin, Bucket* bucketEnd) const; #endif size_t getMemoryUse() const; private: const Bucket* computeMax(Bucket* bucketBegin, Bucket* bucketEnd) const; mutable const Bucket* _cachedMaxBucket; size_t* _entryCountRef; const C& _conf; }; template size_t GeoFront::getMemoryUse() const { return 0; } template const B* GeoFront::getMax(B* bucketBegin, B* bucketEnd) const { // the point is that the compiler is more likely to compile this // pre-calculation so that computeMax won't get called in cases // where the maximum has already been computed. if (_cachedMaxBucket != 0) return _cachedMaxBucket; return computeMax(bucketBegin, bucketEnd); } template const B* GeoFront::computeMax (B* bucketBegin, B* bucketEnd) const { MATHIC_ASSERT(_cachedMaxBucket == 0); const B* maxBucket = bucketBegin; while (maxBucket->empty()) { ++maxBucket; MATHIC_ASSERT(maxBucket != bucketEnd); } for (const B* it = maxBucket + 1; it != bucketEnd; ++it) { if (it->empty()) continue; typename C::CompareResult cmp = _conf.compare(it->back(), maxBucket->back()); if (_conf.cmpLessThan(cmp)) continue; if (C::supportDeduplication && _conf.cmpEqual(cmp)) { B* mb = const_cast(maxBucket); mb->setEntry(mb->end() - 1, _conf.deduplicate(mb->back(), it->back())); const_cast(it)->pop_back(); --*_entryCountRef; continue; } maxBucket = it; } MATHIC_ASSERT(maxBucket != bucketEnd); return _cachedMaxBucket = maxBucket; } #ifdef MATHIC_DEBUG template bool GeoFront::debugIsValid(B* bucketBegin, B* bucketEnd) const { if (_cachedMaxBucket == 0) return true; MATHIC_ASSERT(!_cachedMaxBucket->empty()); for (B* bucket = bucketBegin; bucket != bucketEnd; ++bucket) { if (!bucket->empty()) { MATHIC_ASSERT(!_conf.cmpLessThan (_conf.compare(_cachedMaxBucket->back(), bucket->back()))); } } return true; } #endif // ******************************************************************** // GeoFront maintaining an ordered list template class GeoFront { public: GeoFront(const C& conf, size_t& entryCountRef); ~GeoFront() {delete[] _bucketBegin;} Bucket** begin() {return _bucketBegin;} Bucket*const* begin() const {return _bucketBegin;} Bucket** end() {return _bucketEnd;} Bucket*const* end() const {return _bucketEnd;} /** Can contain this many */ void reserveCapacity(size_t newCapacity); void bucketsInvalidated(Bucket* oldBegin, Bucket* newBegin); bool empty() const {return _bucketBegin == _bucketEnd;} void clear(); void insert(Bucket* bucket); void remove(Bucket* bucket); void keyIncreased(Bucket* bucket); void keyDecreased(Bucket* bucket); void swapKeys(Bucket* a, Bucket* b); bool larger(const Bucket* a, const Bucket* b) const; const Bucket* getMax(Bucket* bucketBegin, Bucket* bucketEnd) const; #ifdef MATHIC_DEBUG bool debugIsValid(Bucket* bucketBegin, Bucket* bucketEnd) const; #endif size_t getMemoryUse() const; private: size_t size() const {return _bucketEnd - _bucketBegin;} size_t capacity() const {return _bucketCapacityEnd - _bucketBegin;} Bucket** _bucketBegin; Bucket** _bucketEnd; Bucket** _bucketCapacityEnd; size_t* _entryCountRef; const C& _conf; }; template void GeoFront::clear() { _bucketEnd = _bucketBegin; } template size_t GeoFront::getMemoryUse() const { return capacity() * sizeof(*_bucketBegin); } template GeoFront::GeoFront(const C& conf, size_t& entryCountRef): _bucketBegin(0), _bucketEnd(0), _bucketCapacityEnd(0), _entryCountRef(&entryCountRef), _conf(conf) { MATHIC_ASSERT(C::trackFront); } template void GeoFront::reserveCapacity(size_t newCapacity) { MATHIC_ASSERT(newCapacity >= size()); if (newCapacity == 0) newCapacity = 1; size_t const oldSize = size(); B** const oldBegin = _bucketBegin; B** const oldEnd = _bucketEnd; _bucketBegin = new B*[newCapacity]; _bucketEnd = _bucketBegin + oldSize; _bucketCapacityEnd = _bucketBegin + newCapacity; std::copy(oldBegin, oldEnd, _bucketBegin); // the tokens point into the old space, so map them to an index // and then back to a pointer into the newly allocated memory. for (B** bucket = _bucketBegin; bucket != _bucketEnd; ++bucket) { B** token = (*bucket)->getFrontToken(); token = (token - oldBegin) + _bucketBegin; (*bucket)->setFrontToken(token); } delete[] oldBegin; } template void GeoFront::bucketsInvalidated (B* oldBegin, B* newBegin) { // _buckets points into an array of buckets that has been reallocated, // so we need to go to an index and back to update the pointers // to point into the new memory area. if (empty()) return; for (B** bucket = begin(); bucket != end(); ++bucket) *bucket = (*bucket - oldBegin) + newBegin; } template void GeoFront::insert(B* bucket) { if (!C::trackFront) return; MATHIC_ASSERT(bucket != 0); MATHIC_ASSERT(bucket->_frontPos == 0); MATHIC_ASSERT(!bucket->empty()); if (_bucketEnd == _bucketCapacityEnd) reserveCapacity(size() + 1); *_bucketEnd = bucket; ++_bucketEnd; bucket->_frontPos = end() - 1; keyIncreased(bucket); } template void GeoFront::keyIncreased(B* bucket) { B** pos = bucket->_frontPos; B** begin = this->begin(); for (; pos != begin; --pos) { // move bucket to lower index B& shouldBeGreater = **(pos - 1); typename C::CompareResult cmp = _conf.compare(shouldBeGreater.back(), bucket->back()); if (!_conf.cmpLessThan(cmp)) break; // todo: if equal *pos = *(pos - 1); shouldBeGreater._frontPos = pos; } // We don't have to adjust bucket's position if it never moved, but // detecting that without extra branches makes the code too complex // for it to be worth it. *pos = bucket; bucket->_frontPos = pos; } template void GeoFront::keyDecreased(B* bucket) { if (bucket->empty()) { remove(bucket); return; } B** pos = bucket->_frontPos; B** end = this->end(); for (; pos + 1 != end; ++pos) { // move bucket to higher index B& otherBucket = **(pos + 1); typename C::CompareResult cmp = _conf.compare(bucket->back(), otherBucket.back()); if (!_conf.cmpLessThan(cmp)) { if (!C::supportDeduplication || !_conf.cmpEqual(cmp)) break; // greater than, found correct position otherBucket.setEntry(otherBucket.end() - 1, _conf.deduplicate(bucket->back(), otherBucket.back())); bucket->pop_back(); --*_entryCountRef; if (bucket->empty()) { bucket->_frontPos = pos; remove(bucket); return; } } *pos = *(pos + 1); otherBucket._frontPos = pos; } // We don't have to adjust bucket's position if it never moved, but // detecting that without extra branches makes the code too complex // for it to be worth it. *pos = bucket; bucket->_frontPos = pos; } template void GeoFront::remove(B* bucket) { MATHIC_ASSERT(bucket->_frontPos != 0); MATHIC_ASSERT(bucket->empty()); B** end = this->end(); // can't dereference end for (B** i = bucket->_frontPos + 1; i != end; ++i) { *(i - 1) = *i; (*i)->_frontPos = i - 1; } --_bucketEnd; bucket->_frontPos = 0; } template void GeoFront::swapKeys(B* a, B* b) { MATHIC_ASSERT(a != 0); MATHIC_ASSERT(b != 0); std::swap(a->_frontPos, b->_frontPos); if (a->_frontPos != 0) *a->_frontPos = a; if (b->_frontPos != 0) *b->_frontPos = b; } template bool GeoFront::larger(const B* a, const B* b) const { MATHIC_ASSERT(a != 0); MATHIC_ASSERT(b != 0); return a->_frontPos < b->_frontPos; } template const B* GeoFront::getMax(B* bucketBegin, B* bucketEnd) const { MATHIC_ASSERT(!empty()); return *begin(); } #ifdef MATHIC_DEBUG template bool GeoFront::debugIsValid(B* bucketBegin, B* bucketEnd) const { std::vector nonEmpty; size_t size = bucketEnd - bucketBegin; for (size_t b = 0; b < size; ++b) { if (bucketBegin[b].empty()) { MATHIC_ASSERT(bucketBegin[b]._frontPos == 0); } else { MATHIC_ASSERT(bucketBegin[b]._frontPos != 0); MATHIC_ASSERT(*(bucketBegin[b]._frontPos) == &(bucketBegin[b])); nonEmpty.push_back(&(bucketBegin[b])); } } std::vector frontCopy(_bucketBegin, _bucketEnd); std::sort(nonEmpty.begin(), nonEmpty.end()); std::sort(frontCopy.begin(), frontCopy.end()); MATHIC_ASSERT(std::equal(frontCopy.begin(), frontCopy.end(), nonEmpty.begin())); if (!empty()) { for (B** it = _bucketBegin + 1; it != _bucketEnd; ++it) MATHIC_ASSERT(!_conf.cmpLessThan (_conf.compare((*(it - 1))->back(), (*it)->back()))); } return true; } #endif } #endif mathic-master/src/mathic/Geobucket.h000077500000000000000000000621361311555225300177460ustar00rootroot00000000000000#ifndef MATHIC_GEOBUCKET_GUARD #define MATHIC_GEOBUCKET_GUARD #include "stdinc.h" #include #include #include #include #include "GeoFront.h" namespace mathic { enum GeobucketBucketStorage { GeoStorePlain = 0, GeoStoreDoubleBuffer = 1, GeoStoreSameSizeBuffer = 2, GeobucketBucketStorageBegin = 0, GeobucketStorageEnd = 3 }; /** A geobucket priority queue. The Configuration template parameter specifies properties of the geobucket. A configuration object is passed to the constructor of geobucket which makes a copy. After the initial copy no further copies are made. Configuration must have these fields: * A type Entry The elements of the geobucket will have this type. Entry must have a copy constructor. * A type CompareResult Intended to be a bool for "less than" or some other type that can encode "less than", "equal" and "greater than". As the Configuration itself interprets what the values of this type mean, the type can be anything. CompareResult must have a copy constructor. * A const or static method: CompareResult compare(Entry, Entry) It is OK for the two parameters to be const Entry&, but compare must not retain a reference to the Entry. The return value is intended to encode the ordering of the two elements. * A const or static method: bool cmpLessThan(CompareResult) The geobucket calls this on a CompareResult returned from compare(a,b). The return value should be true if and only if a is strictly less than b. * A size_t minBucketSize This is the size of the smallest bucket. Must be at least 1. * A size_t geoBase When a new bucket is added, its capacity is geoBase multiplied by the largest capacity among the buckets in the geobucket. Must be at least two. * A static const size_t insertFactor An insert of size S will be done into the smallest bucket whose total capacity (not free capacity) is at least S * insertFactor. * A static const bool supportDeduplication If this is true, then the geobucket will remove entries that are compared and found to be equal. This requires the use of a method cmpEqual and deduplicate. * A static or const method: bool cmpEqual(CompareResult) The method is only called if supportDeduplication is true. The geobucket calls this on a CompareResult returned from compare(a,b). If the return value is true, then a and b must be equivalent in the ordering imposed by compare and cmpLessThan. When the return value is true, the two elements will be replaced by the return value of deduplicate. * A static or const method: Entry deduplicate(Entry a, Entry b) This method is only called if supportDeduplication is true and cmpEqual(compare(a,b)) is true. The two elements a and b in the geobucket will be replaced by the return value of deduplicate. So the number of elements in the geobucket will decrease by one every time deduplicate is called. * A static const bool minBucketBinarySearch If this field is true, insertions of single elements is done using binary search. Otherwise a linear search is done. * A static const bool trackFront If this field is true, then a sorted list of buckets will be maintained to aid in determining the largest element in the queue. Otherwise a linear search is done through the buckets to find the largest element. * A static const bool premerge Let A be a list of elements and let B be the elements in a bucket. Suppose we are about to merge A and B and put them into the same bucket. If the combined size of A and B is larger than the capacity of the bucket, and premerge is true, then B will be preemptively merged into the next bucket after which A can be copied into the now empty bucket that B previously occupied. If premerge is false, then A and B will be merged, and the overflow will force a merge of the combined A and B into the next bucket. * A static const bool collectMax The meta data of a bucket is kept in a separate memory area from the elements of the bucket. If collectMax is true, then the maximum element of each bucket is copied into the meta data area. The idea is to minimize cache misses caused when pop does a linear scan through the maximum elements. * A static const GeobucketBucketStorage bucketStorage GeoStorePlain = 0, GeoStoreDoubleBuffer = 1, GeoStoreSameSizeBuffer = 2, If this field is GeoStorePlain, then a bucket of capacity S has a memory area of size S. If this field is GeoStoreDoubleBuffer, then every bucket will have two same-size memory areas. Only one of the two memory areas is in use at any one time. That way a merge into the bucket can store its result into the other memory area so that a merge does not require a copy. If this field is GeoStoreSameSizeBuffer, then all buckets use a memory area of the same size as the maximum bucket. A bucket's noted capacity does not change. This way any memory area can be used in place of any other memory area, which makes it possible to do merges with no copies and also the content of two buckets can be swapped with no copies. Cannot be combined with useDoubleBucket. */ template class Geobucket { public: typedef C Configuration; typedef typename Configuration::Entry Entry; Geobucket(const Configuration& configuration); Configuration& getConfiguration() {return _conf;} const Configuration& getConfiguration() const {return _conf;} std::string getName() const; void push(Entry entries); // [begin, end) must be sorted in decreasing order. // If Configuration::supportDeduplication is true, then no value must // be present twice in [begin, end). template void push(It begin, It end); Entry pop(); void clear(); Entry top() const; void decreaseTop(Entry newEntry); bool empty() const; size_t size() const; void print(std::ostream& out) const; template void forAll(T& t) const { for (Bucket* bucket = _bucketBegin; bucket != _bucketEnd; ++bucket) { const Entry* stop = bucket->end(); for (const Entry* entry = bucket->begin(); entry != stop; ++entry) { if (!t.proceed(*entry)) { MATHIC_ASSERT(isValid()); return; } } } MATHIC_ASSERT(isValid()); } size_t getMemoryUse() const; private: Geobucket(const Geobucket&); // unavailable Geobucket& operator=(const Geobucket&); // unavailable public: // MES: clang complains when this is private (in GeoFront.h) struct Bucket { Bucket(size_t capacity, Entry* buffer, Entry* otherBuffer); size_t size() const {return _size;} size_t capacity() const {return _capacity;} Entry* begin() {return _begin;} Entry* end() {return begin() + size();} const Entry* begin() const {return _begin;} const Entry* end() const {return begin() + size();} bool empty() const {return size() == 0;} const Entry& back() const { MATHIC_ASSERT(!empty()); return Configuration::collectMax ? _back : *(end() - 1); } const Entry& operator[](size_t i) const { MATHIC_ASSERT(i < size()); return *(begin() + i); } void pop_back() { MATHIC_ASSERT(size() > 0); --_size; if (Configuration::collectMax && _size > 0) _back = *(end() - 1); } void setEntry(Entry* pos, const Entry& entry) { MATHIC_ASSERT(begin() <= pos && pos < end()); *pos = entry; if (Configuration::collectMax && pos == end() - 1) _back = entry; } void insertAtNotEnd(Entry* pos, const Entry& entry) { MATHIC_ASSERT(begin() <= pos && pos < end()); for (Entry* it = end(); it != pos; --it) *it = *(it - 1); *pos = entry; ++_size; } void setBuffer(Entry* buffer) { std::copy(begin(), end(), buffer); _begin = buffer; } void setBufferWithNewEntries(Entry* buffer, size_t size) { _begin = buffer; _size = size; if (size > 0) _back = *(end() - 1); } void setOtherBuffer(Entry* otherBuffer) { MATHIC_ASSERT(Configuration::bucketStorage == GeoStoreDoubleBuffer); _otherBuffer = otherBuffer; } Entry* getOtherBuffer() { MATHIC_ASSERT(Configuration::bucketStorage == GeoStoreDoubleBuffer); return _otherBuffer; } void switchToOtherBuffer(size_t size) { MATHIC_ASSERT(Configuration::bucketStorage == GeoStoreDoubleBuffer); std::swap(_begin, _otherBuffer); _size = size; if (size > 0) _back = *(end() - 1); } void clear() { _size = 0; } template void assign(It begin, It end, size_t size) { MATHIC_ASSERT(static_cast(end - begin) == size); std::copy(begin, end, _begin); _size = size; if (size > 0) _back = *(end - 1); } template void merge(Geobucket& gb, It1 begin1, It1 end1, It2 begin2, It2 end2) { Entry* end = gb.merge(begin1, end1, begin2, end2, _begin); _size = end - _begin; if (_size > 0) _back = *(end - 1); } void push_back(const Entry& e) { MATHIC_ASSERT(size() < capacity()); *(_begin + _size) = e; ++_size; if (Configuration::collectMax) _back = e; } Bucket** getFrontToken() {return _frontPos;} const Bucket** getFrontToken() const {return _frontPos;} void setFrontToken(Bucket** token) {_frontPos = token;} Bucket** _frontPos; private: Entry* _otherBuffer; Entry _back; Entry* _begin; size_t _size; size_t _capacity; }; void addBucket(); template struct Premerge {}; template void insert(Bucket* bucket, It begin, It end, size_t size, Premerge); template void insert(Bucket* bucket, It begin, It end, size_t size, Premerge); template ResIt merge(It1 begin1, It1 end1, It2 begin2, It2 end2, ResIt res); template size_t singleInsert(It begin, size_t size, const Entry& value) const; void moveToEmpty(Bucket& to, Bucket& from); template void mergeToEmpty(Bucket& to, Bucket& from, It begin, It end); void mergeToNonEmpty(Bucket& into, Bucket& from); template void mergeToNonEmpty(Bucket& into, It begin, It end); size_t _geoBase; std::vector _buckets; Bucket* _bucketBegin; Bucket* _bucketEnd; std::vector _mem; Entry* _tmp; // has capacity equal to the largest bucket size_t _entryCount; // Has capacity equal to the largest bucket. Only used when // C::premerge is false. Entry* _tmpForNoPremerge; Configuration _conf; GeoFront _front; /// Asserts internal invariants if asserts are turned on. bool isValid() const; }; template Geobucket::Geobucket(const C& configuration): _bucketBegin(0), _bucketEnd(0), _tmp(0), _entryCount(0), _tmpForNoPremerge(0), _conf(configuration), _front(_conf, _entryCount) { MATHIC_ASSERT(_conf.geoBase > 1); addBucket(); // this avoids the special case of no buckets. MATHIC_ASSERT_NO_ASSUME(_front.debugIsValid(_bucketBegin, _bucketEnd)); } template std::string Geobucket::getName() const { std::ostringstream out; out << "Geobucket(" << 'b' << _conf.geoBase << 'm' << _conf.minBucketSize << 'i' << C::insertFactor << (C::minBucketBinarySearch ? " mbin" : "") << (C::trackFront ? " tf" : "") << (C::supportDeduplication ? " dedup" : "") << (C::premerge ? " prem" : "") << (C::collectMax ? " col" : "") << (C::bucketStorage == GeoStoreDoubleBuffer ? " db" : "") << (C::bucketStorage == GeoStoreSameSizeBuffer ? " ss" : "") << ')'; return out.str(); } template void Geobucket::push(Entry entry) { ++_entryCount; Bucket& bucket = *_bucketBegin; if (bucket.size() == bucket.capacity()) { const Entry* p = &entry; insert(_bucketBegin, p, p + 1, 1, Premerge()); return; } if (bucket.empty()) { bucket.push_back(entry); _front.insert(&bucket); } else if (C::minBucketBinarySearch) { size_t range = bucket.size(); Entry* begin = bucket.begin(); while (true) { // invariant: the position is in the range [begin, begin + range]. if (range == 0) { if (begin == bucket.end()) { bucket.push_back(entry); _front.keyIncreased(&bucket); } else bucket.insertAtNotEnd(begin, entry); break; } Entry* mid = begin + range / 2; typename C::CompareResult cmp = _conf.compare(entry, *mid); if (_conf.cmpLessThan(cmp)) range /= 2; else if (!C::supportDeduplication || !_conf.cmpEqual(cmp)) { begin = mid; ++begin; range -= range / 2 + 1; } else { --_entryCount; bucket.setEntry(mid, _conf.deduplicate(*mid, entry)); break; } } } else { Entry* end = bucket.end(); for (Entry* pos = bucket.begin(); pos != end; ++pos) { typename C::CompareResult cmp = _conf.compare(entry, *pos); if (_conf.cmpLessThan(cmp)) { bucket.insertAtNotEnd(pos, entry); return; } if (C::supportDeduplication && _conf.cmpEqual(cmp)) { bucket.setEntry(pos, _conf.deduplicate(*pos, entry)); --_entryCount; return; } } bucket.push_back(entry); _front.keyIncreased(&bucket); } } template template void Geobucket::push(It begin, It end) { #ifdef MATHIC_DEBUG if (begin != end) { for (It it = begin; it + 1 != end; ++it) { // deduplication assumes that [begin, end) does not contain // duplicates for efficiency, so support for deduplication implies // that no element can be duplicated within a pushed range. if (C::supportDeduplication) { MATHIC_ASSERT(_conf.cmpLessThan(_conf.compare(*(it + 1), *it))); } else { MATHIC_ASSERT(!_conf.cmpLessThan(_conf.compare(*it, *(it + 1)))); } } } #endif const size_t entryCount = end - begin; const size_t adjCount = entryCount * C::insertFactor; _entryCount += entryCount; while (adjCount > (_bucketEnd - 1)->capacity()) addBucket(); for (Bucket* bucket = _bucketBegin; ; ++bucket) { MATHIC_ASSERT(bucket != _bucketEnd); if (adjCount <= bucket->capacity()) { std::reverse_iterator rBegin(end); std::reverse_iterator rEnd(begin); insert(bucket, rBegin, rEnd, entryCount, Premerge()); break; } } MATHIC_SLOW_ASSERT(isValid()); } template void Geobucket::clear() { MATHIC_ASSERT(isValid()); _entryCount = 0; _front.clear(); for (Bucket* bucket = _bucketBegin; bucket != _bucketEnd; ++bucket) bucket->clear(); MATHIC_ASSERT(isValid()); } template typename Geobucket::Entry Geobucket::pop() { Bucket* maxBucket = const_cast(_front.getMax(_bucketBegin, _bucketEnd)); Entry top = maxBucket->back(); maxBucket->pop_back(); --_entryCount; _front.keyDecreased(maxBucket); MATHIC_SLOW_ASSERT(isValid()); return top; } template typename Geobucket::Entry Geobucket::top() const { MATHIC_ASSERT(!empty()); return _front.getMax(_bucketBegin, _bucketEnd)->back(); } template void Geobucket::decreaseTop(Entry newEntry) { MATHIC_ASSERT(!empty()); pop(); push(newEntry); } template size_t Geobucket::size() const { #ifdef MATHIC_DEBUG size_t sum = 0; for (size_t b = 0; b < _buckets.size(); ++b) sum += _buckets[b].size(); MATHIC_ASSERT(sum == _entryCount); #endif return _entryCount; } template bool Geobucket::empty() const { return size() == 0; } template void Geobucket::print(std::ostream& out) const { out << getName() << ": {\n"; for (const Bucket* bucket = _bucketBegin; bucket != _bucketEnd; ++bucket) { out << ' ' << (bucket - _bucketBegin) << ":"; if (bucket->size() > 4) { out << ' ' << (*bucket)[0] << ' ' << (*bucket)[1] << " ... " << (*bucket)[bucket->size() - 2] << ' ' << (*bucket)[bucket->size() - 1]; } else for (size_t i = 0; i < bucket->size(); ++i) out << ' ' << (*bucket)[i]; out << " [" << bucket->size() << '/' << bucket->capacity() << "]\n"; } out << "}\n"; } template void Geobucket::addBucket() { // calculate required amount of memory const size_t newBucketSize = _bucketBegin == _bucketEnd ? _conf.minBucketSize : (_bucketEnd - 1)->capacity() * _conf.geoBase; size_t required = 0; typedef typename std::vector::iterator It; for (Bucket* it = _bucketBegin; it != _bucketEnd; ++it) { required += C::bucketStorage == GeoStoreSameSizeBuffer ? newBucketSize : it->capacity(); if (C::bucketStorage == GeoStoreDoubleBuffer) required += it->capacity(); // for other buffer } required += newBucketSize; // for new bucket if (C::bucketStorage == GeoStoreDoubleBuffer) required += newBucketSize; // for other buffer required += newBucketSize; // for _tmp if (!C::premerge) required += newBucketSize; // for _tmpForNoPremerge // allocate new memory std::vector newMem(required); std::copy(_mem.begin(), _mem.end(), newMem.begin()); // move to new memory buffer size_t offset = 0; for (Bucket* it = _bucketBegin; it != _bucketEnd; ++it) { it->setBuffer(&(newMem[offset])); offset += C::bucketStorage == GeoStoreSameSizeBuffer ? newBucketSize : it->capacity(); if (C::bucketStorage == GeoStoreDoubleBuffer) { it->setOtherBuffer(&(newMem[offset])); offset += it->capacity(); } } Entry* buffer = &(newMem[offset]); offset += newBucketSize; Entry* otherBuffer = 0; if (C::bucketStorage == GeoStoreDoubleBuffer) { otherBuffer = &(newMem[offset]); offset += newBucketSize; } // redirect pointers in _front to point to new memory for _buckets Bucket* oldBucketBegin = _bucketBegin; _buckets.push_back(Bucket(newBucketSize, buffer, otherBuffer)); _bucketBegin = &_buckets.front(); _bucketEnd = _bucketBegin + _buckets.size(); _front.bucketsInvalidated(oldBucketBegin, _bucketBegin); _front.reserveCapacity(_bucketEnd - _bucketBegin); _tmp = &(newMem[offset]); offset += newBucketSize; if (!C::premerge) { _tmpForNoPremerge = &(newMem[offset]); offset += newBucketSize; } MATHIC_ASSERT(offset == required); _mem.swap(newMem); } template void Geobucket::mergeToNonEmpty(Bucket& to, Bucket& from) { MATHIC_ASSERT(!to.empty()); MATHIC_ASSERT(!from.empty()); MATHIC_ASSERT(&to != &from); MATHIC_ASSERT(to.size() + from.size() <= to.capacity()); if (!C::trackFront || _front.larger(&from, &to)) _front.swapKeys(&to, &from); mergeToNonEmpty(to, from.begin(), from.end()); from.clear(); _front.remove(&from); } template template void Geobucket::mergeToNonEmpty(Bucket& into, It begin, It end) { // todo: template select instead of if // todo: into => to MATHIC_ASSERT(!into.empty()); MATHIC_ASSERT(begin != end); MATHIC_ASSERT(static_cast(end - begin) <= into.capacity()); if (C::bucketStorage == GeoStoreDoubleBuffer) { Entry* other = into.getOtherBuffer(); Entry* otherEnd = merge(into.begin(), into.end(), begin, end, other); into.switchToOtherBuffer(otherEnd - other); } else if (C::bucketStorage == GeoStoreSameSizeBuffer) { Entry* tmpEnd = merge(into.begin(), into.end(), begin, end, _tmp); Entry* previousBufferOfInto = into.begin(); into.setBufferWithNewEntries(_tmp, tmpEnd - _tmp); _tmp = previousBufferOfInto; } else { Entry* tmpEnd = std::copy(into.begin(), into.end(), _tmp); into.merge(*this, begin, end, _tmp, tmpEnd); } _front.keyIncreased(&into); } template template void Geobucket::mergeToEmpty(Bucket& to, Bucket& from, It begin, It end) { MATHIC_ASSERT(to.empty()); MATHIC_ASSERT(!from.empty()); // so has place in front MATHIC_ASSERT(&to != &from); MATHIC_ASSERT(begin != end); MATHIC_ASSERT(static_cast(end - begin) + from.size() <= to.capacity()); to.merge(*this, begin, end, from.begin(), from.end()); from.clear(); _front.swapKeys(&from, &to); _front.keyIncreased(&to); } template void Geobucket::moveToEmpty(Bucket& to, Bucket& from) { MATHIC_ASSERT(&to != &from); MATHIC_ASSERT(to.empty()); MATHIC_ASSERT(!from.empty()); MATHIC_ASSERT(from.size() <= to.capacity()); if (C::bucketStorage == GeoStoreSameSizeBuffer) { Entry* previousBufferOfTo = to.begin(); to.setBufferWithNewEntries(from.begin(), from.size()); from.setBufferWithNewEntries(previousBufferOfTo, 0); } else { to.assign(from.begin(), from.end(), from.size()); from.clear(); } _front.swapKeys(&from, &to); } template template void Geobucket::insert (Bucket* p, It begin, It end, size_t incomingSize, Premerge) { MATHIC_ASSERT(!C::premerge); MATHIC_ASSERT(incomingSize == static_cast(end - begin)); MATHIC_ASSERT(0 < incomingSize); MATHIC_ASSERT(begin != end); size_t b = p - _bucketBegin; Bucket& bucket = _buckets[b]; if (bucket.empty()) { bucket.assign(begin, end, incomingSize); _front.insert(&bucket); return; } if (bucket.size() + incomingSize <= bucket.capacity()) { mergeToNonEmpty(bucket, begin, end); return; } size_t accumulatedSize = bucket.size() + incomingSize; for (size_t i = b + 1; ; ++i) { if (i == _buckets.size()) addBucket(); // can invalidate bucket reference variable accumulatedSize += _buckets[i].size(); if (accumulatedSize <= _buckets[i].capacity()) break; } // deal with first step separately as the iterator can have // different type (grrrrr) Bucket& current = _buckets[b]; MATHIC_ASSERT(b + 1 < _buckets.size()); Bucket& next = _buckets[b + 1]; if (next.empty()) { mergeToEmpty(next, current, begin, end); return; } Entry* tmpForNoPremergeEnd = merge( begin, end, current.begin(), current.end(), _tmpForNoPremerge); current.clear(); _front.remove(¤t); ++b; while (true) { Bucket& current = _buckets[b]; const size_t predictedSize = (tmpForNoPremergeEnd - _tmpForNoPremerge) + current.size(); if (predictedSize <= current.capacity()) { mergeToNonEmpty(current, _tmpForNoPremerge, tmpForNoPremergeEnd); return; } MATHIC_ASSERT(b + 1 < _buckets.size()); Bucket& next = _buckets[b + 1]; if (next.empty()) { mergeToEmpty(next, current, _tmpForNoPremerge, tmpForNoPremergeEnd); return; } tmpForNoPremergeEnd = merge(_tmpForNoPremerge, tmpForNoPremergeEnd, current.begin(), current.end(), _tmp); std::swap(_tmp, _tmpForNoPremerge); current.clear(); _front.remove(¤t); ++b; } } template template void Geobucket::insert (Bucket* bucket, It begin, It end, size_t size, Premerge) { MATHIC_ASSERT(C::premerge); // ** determine premerge range (bucket, rbegin] Bucket* rbegin = bucket; size_t incomingSize = size; while (true) { if (rbegin->size() + incomingSize <= rbegin->capacity()) break; incomingSize = rbegin->size(); // this will be incoming for next bucket ++rbegin; if (rbegin == _bucketEnd) { Bucket* oldBucketBegin = _bucketBegin; addBucket(); bucket = (bucket - oldBucketBegin) + _bucketBegin; rbegin = (rbegin - oldBucketBegin) + _bucketBegin; break; } } // ** perform premerges if (bucket != rbegin) { if (!rbegin->empty()) { mergeToNonEmpty(*rbegin, *(rbegin - 1)); --rbegin; } for (Bucket* rit = rbegin; rit != bucket; --rit) moveToEmpty(*rit, *(rit - 1)); } // ** perform insertion if (bucket->empty()) { bucket->assign(begin, end, size); _front.insert(bucket); } else mergeToNonEmpty(*bucket, begin, end); } template template ResIt Geobucket::merge (It1 begin1, It1 end1, It2 begin2, It2 end2, ResIt res) { if (begin1 == end1) goto range1Done; if (begin2 == end2) goto range2Done; while (true) { typename C::CompareResult cmp = _conf.compare(*begin1, *begin2); if (_conf.cmpLessThan(cmp)) { *res = *begin1; ++res; ++begin1; if (begin1 == end1) goto range1Done; } else if (!C::supportDeduplication || !_conf.cmpEqual(cmp)) { *res = *begin2; ++res; ++begin2; if (begin2 == end2) goto range2Done; } else { *res = _conf.deduplicate(*begin1, *begin2); ++res; ++begin1; ++begin2; --_entryCount; if (begin1 == end1) goto range1Done; if (begin2 == end2) goto range2Done; } } range1Done: return std::copy(begin2, end2, res); range2Done: return std::copy(begin1, end1, res); } template Geobucket::Bucket::Bucket (size_t capacity, Entry* buffer, Entry* otherBuffer): _frontPos(0), _otherBuffer(otherBuffer), _begin(buffer), _size(0), _capacity(capacity) { MATHIC_ASSERT(C::bucketStorage == GeoStoreDoubleBuffer ? otherBuffer != 0 : otherBuffer == 0); } template size_t Geobucket::getMemoryUse() const { return _mem.capacity() * sizeof(_mem.front()) + _buckets.capacity() * sizeof(_buckets.front()) + _front.getMemoryUse(); } template bool Geobucket::isValid() const { #ifndef MATHIC_DEBUG return true; #else MATHIC_ASSERT(_conf.geoBase >= 2); MATHIC_ASSERT(!_buckets.empty()); MATHIC_ASSERT(_bucketBegin == &_buckets.front()); MATHIC_ASSERT(_bucketEnd == _bucketBegin + _buckets.size()); MATHIC_ASSERT(_buckets.front().capacity() >= 1); size_t entryCount = 0; for (size_t b = 0; b < _buckets.size(); ++b) { const Bucket& bucket = _buckets[b]; entryCount += bucket.size(); if (bucket.empty()) continue; for (const Entry* it = bucket.begin(); it != bucket.end() - 1; ++it) { MATHIC_ASSERT(!_conf.cmpLessThan(_conf.compare(*(it + 1), *it))); } } MATHIC_ASSERT(entryCount == _entryCount); return _front.debugIsValid(_bucketBegin, _bucketEnd); #endif } }; #endif mathic-master/src/mathic/HashTable.h000077500000000000000000000226071311555225300176700ustar00rootroot00000000000000// MathicGB copyright 2012 all rights reserved. MathicGB comes with ABSOLUTELY // NO WARRANTY and is licensed as GPL v2.0 or later - see LICENSE.txt. // issues: // 1. memory management of nodes // 2. statistics gathering // 3. resizing // 4. put ASSERT's in, to check for all manner of contracts // Notes to self: // see http://attractivechaos.wordpress.com/2008/08/28/comparison-of-hash-table-libraries/ #ifndef MATHIC_HASHTABLE_GUARD #define MATHIC_HASHTABLE_GUARD #include "stdinc.h" #include #include #include #include namespace mathic { template class HashTable; class BasicHashTableConfiguration { typedef int Key; typedef int Value; size_t hash(Key k); bool keysEqual(Key k1, Key k2); }; template class HashTable; template class HashTable { public: typedef C Configuration; typedef typename C::Key Key; typedef typename C::Value Value; // Allowed actions for a Node* returned by lookup or insert: // 1. Key is const, while the Node* is in the hash table. // 2. Value can be modified by the callee at any time // 3. The 'next' field should not be referenced. // As for allocating and deallocating Node*: // Do not allocate your own: only use Node* 's returned by the package // There is no need to deallocate a Node*: when a 'reset() is done, all // Node* 's which have been allocated are deallocated at one time. // When this happens, the Key and Value are not deallocated? // If 'remove' returns a Node*, then it is safe to change the key and/or value, e.g. // to free the space pointed to by 'key' (if that is a pointer value, for instance). class Handle { public: friend class HashTable; Handle(Key k, Value v): next(0), entry(k,v) {} const Key& key() const {return entry.first;} const Value& value() const {return entry.second;} Value& value() {return entry.second;} void setKeyButOnlyDoSoIfThisHandleIsNotInHashTable(Key &new_k) {entry.first=new_k;} private: Handle *next; std::pair entry; }; // Create a hash table HashTable(const Configuration &conf, unsigned int nbits = 10); ~HashTable() {} // Returns the stored configuration. Configuration& configuration() {return mConf;} // Returns the stored configuration. Configuration const& configuration() const {return mConf;} // insert the key 'k' into the hash table. If the key is already there, // and return std::pair(false, ...) // else return std::pair(true, node in the hash table). std::pair insert(Key const& k, Value const& v); // If 'k' is present in the hash table, then its 'Node*' is returned. // If not, then NULL is returned. Handle* lookup(const Key &k); // remove 'p' from the hash table. 'p' itself is also removed. // what about the entries in 'p'? Are the destructors called? void remove(Handle* & p); void reset(); // Major assumption: all nodes have been removed from the table already void hardReset(); // Slow, avoid if possible. // Returns how many bytes of memory this data structure consumes // not including sizeof(*this). size_t memoryUse() const; // Returns a string that describes how this data structure was // configured. std::string name() const; private: Handle* makeNode(const Key &k, const Value &v); void grow(unsigned int nbits); // Used for consistency checking. Returns the number of nodes in the table. // Should match mNodeCount. size_t computeNodeCount() const; // Used for consistency checking. Returns the number of nonempty bins in the hash table. // Should match mBinCount. size_t computeBinCount() const; size_t mHashMask; // this is the number, in binary: 00001111...1, where // the number of 1's is mLogTableSize size_t mTableSize; size_t mLogTableSize; // number of bits in the table: mTableSize should be 2^mLogTableSize size_t mNodeCount; // current number of nodes in the hash table size_t mBinCount; // number of nonzero bins size_t mMaxCountBeforeRebuild; // tweakable parameters double mRebuildThreshold; bool mAlwaysInsertAtEnd; memt::BufferPool mNodePool; std::vector mHashTable; Configuration mConf; }; template HashTable::HashTable(const Configuration &conf, unsigned int nbits): mLogTableSize(nbits), mTableSize(static_cast(1) << nbits), mHashMask((static_cast(1) << nbits) - 1), mNodeCount(0), mBinCount(0), mRebuildThreshold(0.1), mAlwaysInsertAtEnd(true), mNodePool(sizeof(Handle)), mConf(conf) { mHashTable.resize(mTableSize); mMaxCountBeforeRebuild = static_cast(mRebuildThreshold * mTableSize); } template void HashTable::reset() { mNodePool.freeAllBuffers(); } template typename HashTable::Handle *HashTable::makeNode(const Key &k, const Value &v) { mNodeCount++; void *buf = mNodePool.alloc(); Handle* result = new (buf) Handle(k,v); return result; } template std::pair::Handle *> HashTable::insert(const Key &k, const Value &v) { size_t hashval = mConf.hash(k) & mHashMask; MATHIC_ASSERT(hashval < mHashTable.size()); Handle *tmpNode = mHashTable[hashval]; Handle *result = 0; if (tmpNode == 0) { result = makeNode(k,v); mHashTable[hashval] = result; } else { while (true) { if (mConf.keysEqual(tmpNode->key(), k)) { result = tmpNode; return std::pair(false,result); } if (tmpNode->next == 0) { // time to insert the monomial result = makeNode(k, v); if (mAlwaysInsertAtEnd) { tmpNode->next = result; } else { result->next = mHashTable[hashval]; mHashTable[hashval] = result; } break; } tmpNode = tmpNode->next; } } if (mNodeCount > mMaxCountBeforeRebuild) grow(static_cast(mLogTableSize + 2)); // increase by a factor of 4?? MATHIC_ASSERT(computeNodeCount() == mNodeCount); return std::pair(true,result); } template typename HashTable::Handle * HashTable::lookup(const Key &k) { size_t hashval = mConf.hash(k) & mHashMask; MATHIC_ASSERT(hashval < mHashTable.size()); for (Handle *p = mHashTable[hashval]; p != 0; p = p->next) { if (mConf.keysEqual(p->key(), k)) return p; } return NULL; } template void HashTable::remove(Handle *& p) { mNodeCount--; size_t const hashval = mConf.hashvalue(p->key) & mHashMask; Handle head; Handle* tmpNode = mHashTable[hashval]; head.next = tmpNode; for (Handle* q = &head; q->next != 0; q = q->next) { if (q->next == p) { q->next = p->next; mHashTable[hashval] = head.next; if (head.next == 0) mBinCount--; //TODO: call destructor for pair, then call 'free' with the mNodePool return; } } // If we get here, then the node is not at its supposed hash value. // That probably means either that the node has been deleted twice // or that the value in the node changed so that its hash value // changed. That is not allowed. MATHIC_ASSERT(false); } template void HashTable::grow(unsigned int new_nbits) { MATHIC_ASSERT(computeNodeCount() == mNodeCount); size_t const old_table_size = mTableSize; mTableSize = static_cast(1) << new_nbits; mLogTableSize = new_nbits; mHashMask = mTableSize-1; std::vector old_table(mTableSize); std::swap(old_table, mHashTable); mBinCount = 0; for (size_t i = 0; i < old_table_size; ++i) { Handle *p = old_table[i]; while (p != 0) { Handle *q = p; p = p->next; q->next = 0; // Reinsert node. We know that it is unique size_t hashval = mConf.hash(q->key()) & mHashMask; Handle *r = mHashTable[hashval]; if (r == 0) mBinCount++; if (r == 0 || !mAlwaysInsertAtEnd) { q->next = r; mHashTable[hashval] = q; } else { // put it at the end for ( ; r->next != 0; r = r->next) { } r->next = q; } } } mMaxCountBeforeRebuild = static_cast(std::floor(mTableSize * mRebuildThreshold)); MATHIC_ASSERT(computeNodeCount() == mNodeCount); } template size_t HashTable::memoryUse() const { size_t result = mHashTable.capacity() * sizeof(Handle *); result += mNodePool.getMemoryUse(); return result; } template size_t HashTable::computeNodeCount() const { size_t result = 0; for (size_t i=0; inext) result++; } return result; } template size_t HashTable::computeBinCount() const { size_t result = 0; for (size_t i=0; i std::string HashTable::name() const { return std::string("HashTable"); } } // namespace mathic #endif // Local Variables: // indent-tabs-mode: nil // mode: c++ // compile-command: "make -C $MATHIC/mathic " // End: mathic-master/src/mathic/Heap.h000077500000000000000000000124021311555225300167020ustar00rootroot00000000000000#ifndef MATHIC_HEAP_GUARD #define MATHIC_HEAP_GUARD #include "stdinc.h" #include "ComTree.h" #include #include #include namespace mathic { /** A heap priority queue. Configuration serves the same role as for Geobucket. It must have these fields that work as for Geobucket. * A type Entry * A type CompareResult * A const or static method: CompareResult compare(Entry, Entry) * A const or static method: bool cmpLessThan(CompareResult) * A static const bool supportDeduplication * A static or const method: bool cmpEqual(CompareResult) It also has these additional fields: * A static const bool fastIndex If this field is true, then a faster way of calculating indexes is used. This requires sizeof(Entry) to be a power of two! This can be achieved by adding padding to Entry, but this class does not do that for you. */ template class Heap { public: typedef C Configuration; typedef typename Configuration::Entry Entry; Heap(const Configuration& configuration): _conf(configuration) {} Heap(const Configuration&& configuration): _conf(std::move(configuration)) {} Heap(Heap&& heap): _tree(std::move(heap._tree)), _conf(std::move(heap._conf)) {} Configuration& getConfiguration() {return _conf;} const Configuration& getConfiguration() const {return _conf;} template void forAll(T& t) const { Node stop = _tree.lastLeaf().next(); for (Node it = Node(); it != stop; ++it) if (!t.proceed(_tree[it])) return; } std::string getName() const; void push(Entry entry); template void push(It begin, It end); void clear(); Entry pop(); Entry top() const {return _tree[Node()];} bool empty() const {return _tree.empty();} size_t size() const {return _tree.size();} void print(std::ostream& out) const; void decreaseTop(Entry newEntry); size_t getMemoryUse() const; private: typedef ComTree Tree; typedef typename Tree::Node Node; Node moveHoleDown(Node hole); void moveValueUp(Node pos, Entry value); /// Asserts internal invariants if asserts are turned on. bool isValid() const; Tree _tree; Configuration _conf; }; template size_t Heap::getMemoryUse() const { return _tree.getMemoryUse(); } template std::string Heap::getName() const { return std::string("heap(") + (C::fastIndex ? "fi" : "si") + (C::supportDeduplication ? " dedup" : "") + ')'; } template void Heap::push(Entry entry) { _tree.pushBack(entry); moveValueUp(_tree.lastLeaf(), entry); MATHIC_SLOW_ASSERT(isValid()); } template template void Heap::push(It begin, It end) { for (; begin != end; ++begin) push(*begin); } template void Heap::decreaseTop(Entry newEntry) { moveValueUp(moveHoleDown(Node()), newEntry); MATHIC_SLOW_ASSERT(isValid()); } template void Heap::clear() { MATHIC_ASSERT(isValid()); _tree.clear(); MATHIC_ASSERT(isValid()); } template typename Heap::Entry Heap::pop() { Entry top = _tree[Node()]; Entry movedValue = _tree[_tree.lastLeaf()]; _tree.popBack(); if (!_tree.empty()) moveValueUp(moveHoleDown(Node()), movedValue); return top; MATHIC_SLOW_ASSERT(isValid()); } template void Heap::print(std::ostream& out) const { out << getName() << ": {" << _tree << "}\n"; } template typename Heap::Node Heap::moveHoleDown(Node hole) { const Node firstWithout2Children = _tree.lastLeaf().next().parent(); while (hole < firstWithout2Children) { // can assume hole has two children here Node child = hole.left(); Node sibling = child.next(); if (_conf.cmpLessThan(_conf.compare(_tree[child], _tree[sibling]))) child = sibling; _tree[hole] = _tree[child]; hole = child; } // if we are at a node that has a single left child if (hole == firstWithout2Children && _tree.lastLeaf().isLeft()) { Node child = hole.left(); _tree[hole] = _tree[child]; hole = child; } return hole; } template void Heap::moveValueUp(Node pos, Entry value) { const Node origPos = pos; again: while (!pos.isRoot()) { const Node up = pos.parent(); typename C::CompareResult cmp = _conf.compare(_tree[up], value); if (_conf.cmpLessThan(cmp)) { _tree[pos] = _tree[up]; pos = up; } else if (C::supportDeduplication && _conf.cmpEqual(cmp)) { _tree[up] = _conf.deduplicate(_tree[up], value); if (pos != origPos) { // move elements back Entry tmp = _tree[origPos]; for (Node p = origPos.parent(); p != pos; p = p.parent()) std::swap(tmp, _tree[p]); } pos = origPos; value = _tree[_tree.lastLeaf()]; _tree.popBack(); if (origPos == _tree.lastLeaf().next()) { MATHIC_SLOW_ASSERT(isValid()); return; } goto again; } else break; } _tree[pos] = value; MATHIC_SLOW_ASSERT(isValid()); } template bool Heap::isValid() const { #ifndef MATHIC_DEBUG return true; #else MATHIC_ASSERT(_tree.isValid()); for (Node i = Node().next(); i <= _tree.lastLeaf(); ++i) { MATHIC_ASSERT(!_conf.cmpLessThan(_conf.compare(_tree[i.parent()], _tree[i]))); } return true; #endif } } #endif mathic-master/src/mathic/HelpAction.cpp000077500000000000000000000061671311555225300204210ustar00rootroot00000000000000#include "HelpAction.h" #include "CliParameter.h" #include "error.h" #include "display.h" #include "ColumnPrinter.h" #include "CliParser.h" #include #include namespace mathic { HelpAction::HelpAction() {} const char* HelpAction::name() const { return staticName(); } const char* HelpAction::description() const { return "Giving the parameter 'help' displays a list of the available actions.\n" "Giving the parameters 'help action' displays a detailed description of " "that action.\n"; } const char* HelpAction::shortDescription() const { return "Return information about the command line interface."; } void HelpAction::directOptions( std::vector tokens, CliParser& parser ) { _parser = &parser; if (tokens.size() == 1) _topic = tokens.front(); else if (tokens.size() > 1) reportError("Did not expect second option \"" + tokens[1] + "\"."); } void HelpAction::pushBackParameters(std::vector& parameters) { } namespace { // Helper function for displayActionHelp(). bool paramCmp(CliParameter* a, CliParameter* b) { MATHIC_ASSERT(a != 0); MATHIC_ASSERT(b != 0); return std::string(a->name()) < b->name(); } } void HelpAction::displayActionHelp(Action& action) { std::ostringstream out; out << "Displaying information on action: " << action.name() << "\n\n"; out << action.description() << "\n"; std::vector parameters; action.pushBackParameters(parameters); sort(parameters.begin(), parameters.end(), paramCmp); display(out.str()); if (!parameters.empty()) { fprintf(stderr, "\nThe parameters accepted by %s are as follows.\n", action.name()); typedef std::vector::const_iterator cit; for (cit it = parameters.begin(); it != parameters.end(); ++it) { std::string defaultValue = (*it)->valueAsString(); fprintf(stderr, "\n -%s %s (default is %s)\n", (*it)->name().c_str(), (*it)->argumentType().c_str(), (*it)->valueAsString().c_str()); display((*it)->description(), " "); } } } void HelpAction::performAction() { if (_topic != "") { displayActionHelp(*_parser->createActionWithPrefix(_topic)); return; } std::ostringstream out; out << _parser->helpPreMessage() << '\n'; ColumnPrinter printer; printer.addColumn(false, " "); printer.addColumn(true, " - "); std::vector names; _parser->pushBackRegisteredActionNames(names); for (std::vector::const_iterator it = names.begin(); it != names.end(); ++it) { std::unique_ptr action(_parser->createActionWithPrefix(*it)); printer[0] << action->name() << '\n'; printer[1] << action->shortDescription() << '\n'; } printer.print(out); out << '\n' << _parser->helpPostMessage() << '\n'; display(out.str()); } const char* HelpAction::staticName() { return "help"; } const std::string& HelpAction::topic() const { return _topic; } } mathic-master/src/mathic/HelpAction.h000077500000000000000000000014541311555225300200600ustar00rootroot00000000000000#ifndef MATHIC_HELP_ACTION_GUARD #define MATHIC_HELP_ACTION_GUARD #include "stdinc.h" #include "Action.h" #include namespace mathic { class HelpAction : public Action { public: HelpAction(); virtual void directOptions (std::vector tokens, CliParser& parser); virtual void performAction(); virtual const char* name() const; virtual const char* description() const; virtual const char* shortDescription() const; virtual void pushBackParameters(std::vector& parameters); virtual bool isHelpAction() const {return true;} static const char* staticName(); protected: const std::string& topic() const; private: void displayActionHelp(Action& action); CliParser* _parser; std::string _topic; }; } #endif mathic-master/src/mathic/IntegerParameter.cpp000077500000000000000000000017131311555225300216210ustar00rootroot00000000000000#include "IntegerParameter.h" #include "error.h" #include #include namespace mathic { IntegerParameter::IntegerParameter(const std::string& name, const std::string& description, unsigned int defaultValue): CliParameter(name, description), _value(defaultValue) { } std::string IntegerParameter::argumentType() const { return "INTEGER"; } std::string IntegerParameter::valueAsString() const { std::ostringstream out; out << value(); return out.str(); } void IntegerParameter::processArgument(const std::string& argument) { std::istringstream in(argument); in >> _value; std::ostringstream out; out << _value; if (out.str() != argument) { reportError("The value given to option -" + name() + " was not " "as expected. It must be a non-negative integer in the range " "[0, 2^31-1]."); } } } mathic-master/src/mathic/IntegerParameter.h000077500000000000000000000014561311555225300212720ustar00rootroot00000000000000#ifndef MATHIC_INTEGER_PARAMETER_GUARD #define MATHIC_INTEGER_PARAMETER_GUARD #include "stdinc.h" #include "CliParameter.h" #include #include namespace mathic { class IntegerParameter : public CliParameter { public: IntegerParameter(const std::string& name, const std::string& description, unsigned int defaultValue); unsigned int value() const {return _value;} void setValue(unsigned int value) {_value = value;} operator unsigned int() const {return value();} void operator=(unsigned int value) {setValue(value);} virtual std::string argumentType() const; virtual std::string valueAsString() const; virtual void processArgument(const std::string& argument); private: unsigned int _value; }; } #endif mathic-master/src/mathic/KDEntryArray.h000077500000000000000000000352741311555225300203600ustar00rootroot00000000000000#ifndef MATHIC_K_D_ENTRY_ARRAY_GUARD #define MATHIC_K_D_ENTRY_ARRAY_GUARD #include "stdinc.h" #include "DivMask.h" #include "Comparer.h" #include #include namespace mathic { template class KDEntryArray : public DivMask::HasDivMask { public: typedef typename C::Entry Entry; typedef typename C::Exponent Exponent; typedef EE ExtEntry; typedef EE* iterator; typedef const EE* const_iterator; typedef const EE& const_reference; typedef EE value_type; typedef DivMask::Calculator DivMaskCalculator; using DivMask::HasDivMask::updateToLowerBound; KDEntryArray(memt::Arena& arena, const C& conf); template KDEntryArray(Iter begin, Iter end, memt::Arena& arena, const DivMaskCalculator& calc, const C& conf); template KDEntryArray(Iter begin, Iter end, memt::Arena& arena, const C& conf); void clear(); void recalculateTreeDivMask(); #ifdef MATHIC_DEBUG bool debugIsValid() const; #endif iterator begin() {return reinterpret_cast(_beginMemory);} const_iterator begin() const { return reinterpret_cast(_beginMemory); } iterator end() {return _end;} const_iterator end() const {return _end;} bool empty() const {return begin() == end();} size_t size() const {return std::distance(begin(), end());} EE& front() {MATHIC_ASSERT(!empty()); return *begin();} const EE& front() const {MATHIC_ASSERT(!empty()); return *begin();} EE& back() {MATHIC_ASSERT(!empty()); return *(_end - 1);} const EE& back() const {MATHIC_ASSERT(!empty()); return *(_end - 1);} void push_back(const EE& entry); void pop_back(); void insert(iterator it, const EE& entry); void insert(const EE& entry, const C& conf); /** Returns how many were removed. */ template size_t removeMultiples(const EM& monomial, MO& out, const C& conf); template bool removeElement(const M& monomial, const C& conf); template inline iterator findDivisor(const EM& extMonomial, const C& conf); template inline bool findAllDivisors(const EM& extMonomial, DO& out, const C& conf); template inline bool findAllMultiples (const EM& extMonomial, Output& out, const C& conf); template bool forAll(EO& eo); bool allStrictlyGreaterThan(size_t var, Exponent exp, const C& conf); bool allLessThanOrEqualTo(size_t var, Exponent exp, const C& conf); /** Reorders [begin, iter) and chooses a var and an exp such that if mid is the returned value, then [begin, mid) has less than or equal to exp exponent of var and [mid,end) has strictly greater exponent. The initial value of var is a hint that var + 1 could be a good place to start the search for a suitable value of var. begin must not equal end. If not null, the entry os taken into account when deciding which split to perform. The Entry is NOT inserted into [begin, end). */ template static Iter split( Iter begin, Iter end, size_t& var, Exponent& exp, const C& conf, const ExtEntry* extEntry = 0 ); using DivMask::HasDivMask::resetDivMask; using DivMask::HasDivMask::getDivMask; private: static Entry& getEntry(Entry& e) {return e;} static const Entry& getEntry(const Entry& e) {return e;} static Entry& getEntry(ExtEntry& e) {return e.get();} static const Entry& getEntry(const ExtEntry& e) {return e.get();} KDEntryArray(const KDEntryArray&); // unavailable void operator=(const KDEntryArray&); // unavailable class SplitEqualOrLess; /** This is the memory for the entries. It is kept as a raw char* to avoid constructing all the entries right away. */ char _beginMemory[C::LeafSize * sizeof(ExtEntry)]; iterator _end; // points into _beginMemory #ifdef MATHIC_DEBUG const bool _sortOnInsertDebug; #endif }; template class KDEntryArray::SplitEqualOrLess { public: typedef typename C::Exponent Exponent; typedef typename C::Entry Entry; SplitEqualOrLess(size_t var, const Exponent& exp, const C& conf): _var(var), _exp(exp), _conf(conf) {} bool operator()(const Entry& entry) const { return !(_exp < _conf.getExponent(entry, _var)); } bool operator()(const ExtEntry& entry) const { return !(_exp < _conf.getExponent(entry.get(), _var)); } private: size_t _var; const Exponent& _exp; const C& _conf; }; template template Iter KDEntryArray::split( Iter begin, Iter end, size_t& var, Exponent& exp, const C& conf, const ExtEntry* extEntry ) { MATHIC_ASSERT(begin != end); const size_t varCount = conf.getVarCount(); for (size_t i = 0; i < varCount; ++i) { var = (var + 1) % conf.getVarCount(); typename C::Exponent min; typename C::Exponent max; if (extEntry == 0) { min = conf.getExponent(getEntry(*begin), var); max = conf.getExponent(getEntry(*begin), var); } else { min = conf.getExponent(getEntry(*extEntry), var); max = conf.getExponent(getEntry(*extEntry), var); } for (Iter it = begin; it != end; ++it) { min = std::min(min, conf.getExponent(getEntry(*it), var)); max = std::max(max, conf.getExponent(getEntry(*it), var)); } if (min == max) continue; // this formula for the average avoids overflow exp = min + (max - min) / 2; SplitEqualOrLess cmp(var, exp, conf); return std::partition(begin, end, cmp); } MATHIC_ASSERT(false); throw std::logic_error("ERROR: Inserted duplicate entry into a KD tree."); } template KDEntryArray::KDEntryArray(memt::Arena& arena, const C& conf) #ifdef MATHIC_DEBUG :_sortOnInsertDebug(conf.getSortOnInsert()) #endif { _end = begin(); } template template KDEntryArray::KDEntryArray( Iter begin, Iter end, memt::Arena& arena, const DivMaskCalculator& calc, const C& conf) #ifdef MATHIC_DEBUG :_sortOnInsertDebug(conf.getSortOnInsert()) #endif { MATHIC_ASSERT(static_cast(std::distance(begin, end)) <= C::LeafSize); _end = this->begin(); // cannot directly copy as memory is not constructed. for (; begin != end; ++begin) push_back(EE(*begin, calc, conf)); if (conf.getSortOnInsert()) std::sort(this->begin(), this->end(), Comparer(conf)); } template template KDEntryArray::KDEntryArray( Iter begin, Iter end, memt::Arena& arena, const C& conf) #ifdef MATHIC_DEBUG :_sortOnInsertDebug(conf.getSortOnInsert()) #endif { MATHIC_ASSERT(static_cast(std::distance(begin, end)) <= C::LeafSize); _end = this->begin(); // cannot directly copy as memory is not constructed. for (; begin != end; ++begin) push_back(*begin); if (conf.getSortOnInsert()) std::sort(this->begin(), this->end(), Comparer(conf)); } template void KDEntryArray::push_back(const EE& entry) { MATHIC_ASSERT(size() < C::LeafSize); new (_end) EE(entry); updateToLowerBound(entry); ++_end; } template void KDEntryArray::pop_back() { MATHIC_ASSERT(!empty()); --_end; _end->~EE(); } template void KDEntryArray::insert(iterator it, const EE& entry) { MATHIC_ASSERT(size() < C::LeafSize); if (it == end()) { push_back(entry); return; } push_back(back()); iterator moveTo = end(); for (--moveTo; moveTo != it; --moveTo) *moveTo = *(moveTo - 1); updateToLowerBound(entry); *it = entry; } template void KDEntryArray::insert(const EE& entry, const C& conf) { MATHIC_ASSERT(size() < C::LeafSize); if (!conf.getSortOnInsert()) push_back(entry); else { iterator it = std::upper_bound(begin(), end(), entry, Comparer(conf)); insert(it, entry); } } template void KDEntryArray::clear() { while (!empty()) pop_back(); } template template size_t KDEntryArray::removeMultiples (const EM& monomial, MO& out, const C& conf) { MATHIC_ASSERT(C::AllowRemovals); if (C::LeafSize == 1) { // special case for performance if (empty() || !monomial.divides(*begin(), conf)) return 0; out.push_back(begin()->get()); pop_back(); return 1; } iterator it = begin(); iterator oldEnd = end(); for (; it != oldEnd; ++it) { if (monomial.divides(*it, conf)) { out.push_back(it->get()); break; } } if (it == oldEnd) return 0; iterator newEnd = it; for (++it; it != oldEnd; ++it) { if (!monomial.divides(*it, conf)) { *newEnd = *it; ++newEnd; } else out.push_back(it->get()); } // cannot just set _end directly as the superfluous // entries at the end need to be destructed. const size_t newSize = std::distance(begin(), newEnd); const size_t removedCount = size() - newSize; MATHIC_ASSERT(newSize < size()); do { pop_back(); } while (newSize < size()); MATHIC_ASSERT(size() == newSize); return removedCount; } template template bool KDEntryArray::removeElement(const M& monomial, const C& conf) { const size_t varCount = conf.getVarCount(); const_iterator stop = end(); for (iterator it = begin(); it != stop; ++it) { for (size_t var = 0; var < varCount; ++var) if (conf.getExponent(monomial, var) != conf.getExponent(it->get(), var)) goto skip; if (it != end()) { const_iterator next = it; for (++next; next != end(); ++it, ++next) *it = *next; } pop_back(); return true; skip:; } return false; } template template typename KDEntryArray::iterator KDEntryArray::findDivisor(const EM& extMonomial, const C& conf) { if (C::UseTreeDivMask && C::LeafSize > 1 && // no reason to do it for just 1 leaf !getDivMask().canDivide(extMonomial.getDivMask())) return end(); if (C::LeafSize == 1) { // special case for performance MATHIC_ASSERT(C::AllowRemovals || !empty()); if ((!C::AllowRemovals || !empty()) && begin()->divides(extMonomial, conf)) return begin(); else return end(); } else if (!conf.getSortOnInsert()) { const iterator stop = end(); for (iterator it = begin(); it != stop; ++it) if (it->divides(extMonomial, conf)) return it; return stop; } else { iterator rangeEnd = std::upper_bound(begin(), end(), extMonomial, Comparer(conf)); iterator it = begin(); for (; it != rangeEnd; ++it) if (it->divides(extMonomial, conf)) return it; return end(); } } template template bool KDEntryArray:: findAllDivisors(const EM& extMonomial, DO& out, const C& conf) { if (C::UseTreeDivMask && C::LeafSize > 1 && // no reason to do it for just 1 leaf !getDivMask().canDivide(extMonomial.getDivMask())) return end(); if (C::LeafSize == 1) { // special case for performance MATHIC_ASSERT(C::AllowRemovals || !empty()); return (C::AllowRemovals && empty()) || !begin()->divides(extMonomial, conf) || out.proceed(begin()->get()); } else if (!conf.getSortOnInsert()) { const iterator stop = end(); for (iterator it = begin(); it != stop; ++it) if (it->divides(extMonomial, conf)) if (!out.proceed(it->get())) return false; } else { iterator rangeEnd = std::upper_bound(begin(), end(), extMonomial, Comparer(conf)); iterator it = begin(); for (; it != rangeEnd; ++it) if (it->divides(extMonomial, conf)) if (!out.proceed(it->get())) return false; } return true; } template template bool KDEntryArray:: findAllMultiples(const EM& extMonomial, DO& out, const C& conf) { if (C::LeafSize == 1) { // special case for performance MATHIC_ASSERT(C::AllowRemovals || !empty()); return (C::AllowRemovals && empty()) || !extMonomial.divides(*begin(), conf) || out.proceed(begin()->get()); } // todo: consider making sorted version const iterator stop = end(); for (iterator it = begin(); it != stop; ++it) if (extMonomial.divides(*it, conf)) if (!out.proceed(it->get())) return false; return true; } template template bool KDEntryArray::forAll(EO& output) { if (C::LeafSize == 1) { // special case for performance MATHIC_ASSERT(C::AllowRemovals || !empty()); return (C::AllowRemovals && empty()) || output.proceed(begin()->get()); } const iterator stop = end(); for (iterator it = begin(); it != stop; ++it) if (!output.proceed(it->get())) return false; return true; } template bool KDEntryArray::allStrictlyGreaterThan( size_t var, Exponent exp, const C& conf ) { for (const_iterator it = begin(); it != end(); ++it) if (!(exp < conf.getExponent(it->get(), var))) return false; return true; } template bool KDEntryArray::allLessThanOrEqualTo( size_t var, Exponent exp, const C& conf ) { for (const_iterator it = begin(); it != end(); ++it) if (exp < conf.getExponent(it->get(), var)) return false; return true; } template void KDEntryArray::recalculateTreeDivMask() { if (!C::UseTreeDivMask) return; resetDivMask(); for (const_iterator it = begin(); it != end(); ++it) updateToLowerBound(*it); } #ifdef MATHIC_DEBUG template bool KDEntryArray::debugIsValid() const { MATHIC_ASSERT(C::AllowRemovals || !empty()); MATHIC_ASSERT(static_cast(end() - begin()) <= C::LeafSize); if (C::UseTreeDivMask && C::LeafSize > 1) { for (const_iterator it = begin(); it != end(); ++it) { MATHIC_ASSERT(getDivMask().canDivide(it->getDivMask())); } } return true; } #endif } #endif mathic-master/src/mathic/KDTree.h000077500000000000000000000316671311555225300171610ustar00rootroot00000000000000#ifndef MATHIC_K_D_TREE_GUARD #define MATHIC_K_D_TREE_GUARD #include "stdinc.h" #include "DivMask.h" #include "BinaryKDTree.h" #include "PackedKDTree.h" #include #include #include #include #include #include #include namespace mathic { /** An object that supports queries for divisors of a monomial using a KD Tree (K Dimensional Tree). See DivFinder.h for more documentation. Extra fields for Configuration: * bool getSortOnInsert() const Return true to keep the monomials in leaves sorted to speed up queries. * size_t getLeafSize() const Return the fixed maximal size of a leaf. * static const bool AllowRemovals If false, it is an error to call methods that remove elements from the data structure. This can be a slight speed up in some cases. Clear and rebuild is still allowed even if this field is false. */ template class KDTree; namespace KDTreeInternal { // cannot do this inside KDTree as template partial specializations // cannot be done inside a class. template struct SelectTree { typedef BinaryKDTree Tree; }; template struct SelectTree { typedef PackedKDTree Tree; }; } template class KDTree { private: // for figuring out which kd tree implementation to use typedef typename KDTreeInternal::SelectTree::Tree Tree; typedef typename Tree::ExtEntry ExtEntry; typedef typename Tree::ExtMonoRef ExtMonoRef; public: typedef C Configuration; /** Constructs an object with the given configuration. The configuration is copied into the object, so a reference to the passed-in object is not kept. The configuration is not copied other than the initial copy. */ KDTree(const C& configuration): _divMaskCalculator(configuration), _tree(configuration), _size(0) { resetNumberOfChangesTillRebuild(); if (getConfiguration().getUseDivisorCache()) _divisorCache = 0; } static const bool UseDivMask = C::UseDivMask; typedef typename C::Monomial Monomial; typedef typename C::Entry Entry; typedef typename C::Exponent Exponent; /** Returns whether there are any entries. */ bool empty() const {return size() == 0;} /** Returns the number of entries. */ size_t size() const {return _size;} /** Returns a string that describes the data structure. */ std::string getName() const; /** Returns a reference to this object's configuration object. */ C& getConfiguration() { return _tree.getConfiguration(); } /** Returns a reference to this object's configuration object. */ const C& getConfiguration() const { return const_cast(_tree).getConfiguration(); } /** Removes all multiples of monomial. A duplicate counts as a multiple. Returns true if any multiples were removed. */ bool removeMultiples(const Monomial& monomial) { MATHIC_ASSERT(C::AllowRemovals); if (!C::AllowRemovals) throw std::logic_error("Removal request while removals disabled."); DummyMultipleOutput out; return removeMultiples(monomial, out); } /** Removes all multiples of monomial. A duplicate counts as a multiple. Returns true if any multiples were removed. Calls out.push_back(entry) for each entry that is removed. */ template bool removeMultiples(const Monomial& monomial, MultipleOutput& out) { MATHIC_ASSERT(C::AllowRemovals); if (!C::AllowRemovals) throw std::logic_error("Removal request while removals disabled."); ExtMonoRef extMonomial(monomial, _divMaskCalculator, getConfiguration()); size_t removedCount = _tree.removeMultiples(extMonomial, out); reportChanges(0, removedCount); return removedCount > 0; } /** Calls out.proceed(entry) for each entry that monomial divides. The method returns if proceed returns false, otherwise the search for divisors proceeds. */ template void findAllMultiples(const Monomial& monomial, Output& out) { ExtMonoRef extMonomial(monomial, _divMaskCalculator, getConfiguration()); _tree.findAllMultiples(extMonomial, out); } /** Calls out.proceed(entry) for each entry that monomial divides. The method returns if proceed returns false, otherwise the search for divisors proceeds. */ template void findAllMultiples(const Monomial& monomial, Output& output) const { ConstEntryOutput constOutput(output); const_cast&>(*this).findAllMultiples(monomial, constOutput); } /** Inserts entry into the data structure. Does NOT remove multiples of entry and entry is inserted even if it is a multiple of another entry. */ void insert(const Entry& entry) { ExtEntry extEntry(entry, _divMaskCalculator, getConfiguration()); _tree.insert(extEntry); reportChanges(1, 0); } /** Inserts the entries in the range [begin, end) into the data structure. Does NOT remove multiples of entry and entry is inserted even if it is a multiple of another entry. The elements in the range [begin, end) may be rearranged by this function, so the range must be mutable. If that is not acceptable, call the one element insert method for each element. */ template void insert(Iter begin, Iter end) { if (begin == end) return; const size_t inserted = std::distance(begin, end); if (!empty()) { for (; begin != end; ++begin) _tree.insert(*begin); } else { _tree.insert(begin, end); // insert into empty container is equivalent to rebuild resetNumberOfChangesTillRebuild(); } reportChanges(inserted, 0); } /** Removes an element whose exponents are equal to monomial's. Returns if there are no such monomials in the data structure. */ bool removeElement(const Monomial& monomial) { MATHIC_ASSERT(C::AllowRemovals); if (!C::AllowRemovals) throw std::logic_error("Removal request while removals disabled."); return _tree.removeElement(monomial); } /** Returns a pointer to an entry that divides monomial. Returns null if no entries divide monomial. */ inline Entry* findDivisor(const Monomial& monomial) { // todo: do this on extended monomials. requires cache to be extended. const C& conf = getConfiguration(); if (conf.getUseDivisorCache() && _divisorCache != 0 && conf.divides(*_divisorCache, monomial)) return _divisorCache; ExtMonoRef extMonomial(monomial, _divMaskCalculator, getConfiguration()); Entry* divisor = _tree.findDivisor(extMonomial); if (conf.getUseDivisorCache() && divisor != 0) _divisorCache = divisor; return divisor; } /** Returns the position of a divisor of monomial. Returns null if no entries divide monomial. */ inline const Entry* findDivisor(const Monomial& monomial) const { return const_cast&>(*this).findDivisor(monomial); } /** Calls out.proceed(entry) for each entry that divides monomial. The method returns if proceed returns false, otherwise the search for divisors proceeds. */ template void findAllDivisors(const Monomial& monomial, DivisorOutput& out) { ExtMonoRef extMonomial(monomial, _divMaskCalculator, getConfiguration()); _tree.findAllDivisors(extMonomial, out); } /** Calls output.proceed(entry) for each entry that divides monomial. The method returns if proceed returns false, otherwise the search for divisors proceeds. */ template void findAllDivisors(const Monomial& monomial, DivisorOutput& output) const { ConstEntryOutput constOutput(output); const_cast&>(*this).findAllDivisors(monomial, constOutput); } /** Calls output.proceed(entry) for each entry. The method returns if proceed returns false, otherwise the search for divisors proceeds. */ template void forAll(EntryOutput& out) { _tree.forAll(out); } /** Calls out.proceed(entry) for each entry. The method returns if proceed returns false, otherwise the search for divisors proceeds. */ template void forAll(EntryOutput& output) const { ConstEntryOutput constOutput(output); const_cast&>(*this).forAll(constOutput); } /** Removes all entries. Does not reset the configuration object. */ void clear() { _tree.clear(); resetNumberOfChangesTillRebuild(); _tree.calc().rebuildDefault(getConfiguration()); } /** Rebuilds the data structure. */ void rebuild() { EntryRecorder recorder(memt::Arena::getArena(), size()); _tree.forAll(recorder); _divMaskCalculator.rebuild (recorder.begin(), recorder.end(), getConfiguration()); _tree.reset(recorder.begin(), recorder.end(), _divMaskCalculator); resetNumberOfChangesTillRebuild(); } /** Returns the number of bytes allocated by this object. Does not include sizeof(*this), does not include any additional memory that the configuration may have allocated and does not include any memory that an Entry may point to. Does include sizeof(Entry) as well as unused memory that is being kept to avoid frequent allocations. */ size_t getMemoryUse() const {return _tree.getMemoryUse();} private: KDTree(const KDTree&); // unavailable void operator=(const KDTree&); // unavailable // For recording all entries in the tree using forAll. class EntryRecorder { public: EntryRecorder(memt::Arena& arena, size_t capacity): _entries(arena, capacity) {} bool proceed(const Entry& entry) { _entries.push_back(entry); return true; } Entry* begin() {return _entries.begin();} Entry* end() {return _entries.end();} private: memt::ArenaVector _entries; }; /// makes the parameter given to proceed be const. template class ConstEntryOutput { public: ConstEntryOutput(EntryOutput& out): _out(out) {} bool proceed(const Entry& entry) {return _out.proceed(entry);} private: EntryOutput& _out; }; /// Ignores everything passed to it. */ class DummyMultipleOutput { public: void push_back(Entry& e) {} }; void reportChanges(size_t additions, size_t removals); void resetNumberOfChangesTillRebuild(); bool reportChangesRebuild(size_t additions, size_t removals); size_t _changesTillRebuild; /// Update using reportChanges(). Entry* _divisorCache; /// The divisor in the previous query. Can be null. // All DivMasks calculated using this. typename Tree::DivMaskCalculator _divMaskCalculator; Tree _tree; size_t _size; }; template std::string KDTree::getName() const { std::stringstream out; const C& conf = getConfiguration(); out << "KDTree(" << (C::PackedTree ? "packed" : "binary") << ')'; out << " leaf:" << C::LeafSize; if (UseDivMask && conf.getDoAutomaticRebuilds()) { out << " autob:" << conf.getRebuildRatio() << '/' << conf.getRebuildMin(); } out << (C::UseDivMask && !C::UseTreeDivMask ? " dmask" : "") << (C::UseTreeDivMask ? " tree-dmask" : "") << (conf.getSortOnInsert() ? " sort" : "") << (conf.getUseDivisorCache() ? " cache" : "") << (C::AllowRemovals ? "" : " no-removals"); return out.str(); } template void KDTree::resetNumberOfChangesTillRebuild() { const C& conf = getConfiguration(); if (conf.getUseDivisorCache()) _divisorCache = 0; if (!conf.getDoAutomaticRebuilds()) return; MATHIC_ASSERT(conf.getRebuildRatio() > 0); _changesTillRebuild = std::max (static_cast(size() * conf.getRebuildRatio()), conf.getRebuildMin()); } template void KDTree::reportChanges(size_t additions, size_t removals) { if (getConfiguration().getUseDivisorCache() && (additions | removals) != 0) _divisorCache = 0; if (reportChangesRebuild(additions, removals)) rebuild(); } template bool KDTree::reportChangesRebuild(size_t additions, size_t removals) { // note how negative value/overflow of _changesTillRebuild cannot // happen this way. MATHIC_ASSERT(removals <= size() + additions); _size = (size() + additions) - removals; if (!getConfiguration().getDoAutomaticRebuilds()) return false; const size_t changesMadeCount = additions + removals; if (_changesTillRebuild > changesMadeCount) { _changesTillRebuild -= changesMadeCount; return false; } else return true; } } #endif mathic-master/src/mathic/NameFactory.h000077500000000000000000000163441311555225300202460ustar00rootroot00000000000000#ifndef MATHIC_NAME_FACTORY_GUARD #define MATHIC_NAME_FACTORY_GUARD #include "stdinc.h" #include "error.h" #include #include #include #include namespace mathic { /** A NameFactory takes a name and then creates an instance of a class that has been previously registered under that name. This is done in a general way using templates. None of this is very efficient currently. However, the interface can be implemented much more efficiently if that becomes necessary. */ template class NameFactory { public: /** @param abstractName The name for those things that are being generated in general. Used for error messages. */ NameFactory(const char* abstractName): _abstractName(abstractName) {} typedef std::unique_ptr (*FactoryFunction)(); void registerProduct(const std::string& name, FactoryFunction function); /** Calls the function registered to the parameter name and returns the result. Returns null if name has not been registered. */ std::unique_ptr createNullOnUnknown(const std::string& name) const; /** Calls the function registered to the parameter name and returns the result. Throws an exception if name has not been registered. */ std::unique_ptr create(const std::string& name) const; /** Inserts into names all registered names that have the indicated prefix in lexicographic increasing order. */ void namesWithPrefix (const std::string& prefix, std::vector& names) const; /** Returns the name of the kinds of things being created. */ std::string abstractProductName() const; /** Returns true if no names have been registered. */ bool empty() const; private: typedef std::pair Pair; typedef typename std::vector::const_iterator const_iterator; std::vector _pairs; const std::string _abstractName; }; /** Registers the given name to a function that default-constructs a ConcreteProduct. */ template void nameFactoryRegister (NameFactory& factory, const std::string& name); /** Registers the name ConcreteProduct::staticName() to a function that default-constructs a ConcreteProduct. */ template void nameFactoryRegister (NameFactory& factory); /** Registers the string returned by ConcreteProduct::staticName() to a function that default-constructs a ConcreteProduct. */ template void nameFactoryRegister(NameFactory& factory); /** Creates the unique product that has the indicated prefix, or creates the actual product that has name equal to the indicated prefix. Exceptions thrown are as for uniqueNamesWithPrefix(). */ template std::unique_ptr createWithPrefix (const NameFactory& factory, const std::string& prefix); /** Returns the unique product name that has the indicated prefix, or return prefix itself if it is the actual name of a product. @exception UnknownNameException If no product has the indicated prefix. @exception AmbiguousNameException If more than one product has the indicated prefix and the prefix is not the actual name of any product. */ template std::string uniqueNameWithPrefix (const NameFactory& factory, const std::string& prefix); // ************************************************************** // These implementations have to be included here due // to being templates. template std::unique_ptr NameFactory:: createNullOnUnknown(const std::string& name) const { for (const_iterator it = _pairs.begin(); it != _pairs.end(); ++it) if (it->first == name) return it->second(); return std::unique_ptr(); } template std::unique_ptr NameFactory:: create(const std::string& name) const { std::unique_ptr product = createNullOnUnknown(name); if (product.get() == 0) throwError( "Unknown " + abstractProductName() + " \"" + name + "\"."); return product; } template void NameFactory:: registerProduct(const std::string& name, FactoryFunction function) { MATHIC_ASSERT(createNullOnUnknown(name).get() == 0); // no duplicate names _pairs.push_back(Pair(name, function)); } template void NameFactory::namesWithPrefix( const std::string& prefix, std::vector& names ) const { for (const_iterator it = _pairs.begin(); it != _pairs.end(); ++it) if (it->first.compare(0, prefix.size(), prefix) == 0) names.push_back(it->first); std::sort(names.begin(), names.end()); } template bool NameFactory::empty() const { return _pairs.empty(); } template std::string NameFactory::abstractProductName() const { return _abstractName; } template void nameFactoryRegister(NameFactory& factory) { nameFactoryRegister (factory, ConcreteProduct::staticName()); } template void nameFactoryRegister (NameFactory& factory, const std::string& name) { // work-around for no local functions in old C++ struct HoldsFunction { static std::unique_ptr createConcreteProduct() { return std::unique_ptr(new ConcreteProduct()); } }; factory.registerProduct(name, HoldsFunction::createConcreteProduct); } template std::unique_ptr createWithPrefix (const NameFactory& factory, const std::string& prefix) { return factory.createNullOnUnknown(uniqueNameWithPrefix(factory, prefix)); } template std::string uniqueNameWithPrefix (const NameFactory& factory, const std::string& prefix) { std::vector names; factory.namesWithPrefix(prefix, names); // if exact string found, then use that one even if there are other // prefix matches. if (std::find(names.begin(), names.end(), prefix) != names.end()) { names.clear(); names.push_back(prefix); } if (names.empty()) { throwError ("No " + factory.abstractProductName() + " has the prefix \"" + prefix + "\"."); } if (names.size() >= 2) { std::string errorMsg = "More than one " + factory.abstractProductName() + " has prefix \"" + prefix + "\":\n "; for (size_t name = 0; name < names.size(); ++name) errorMsg += ' ' + names[name]; throwError(errorMsg); } MATHIC_ASSERT(names.size() == 1); return names.back(); } } #endif mathic-master/src/mathic/PackedKDTree.h000077500000000000000000000554231311555225300202650ustar00rootroot00000000000000#ifndef MATHIC_PACKED_K_D_TREE_GUARD #define MATHIC_PACKED_K_D_TREE_GUARD #include "stdinc.h" #include "DivMask.h" #include "KDEntryArray.h" #include #include namespace mathic { template class PackedKDTree { public: typedef typename C::Monomial Monomial; typedef typename C::Entry Entry; typedef typename C::Exponent Exponent; typedef typename DivMask::Extender ExtEntry; typedef typename DivMask::Extender ExtMonoRef; typedef typename DivMask::Calculator DivMaskCalculator; struct ExpOrder { ExpOrder(size_t var, const C& conf): _var(var), _conf(conf) {} bool operator()(const ExtEntry& a, const ExtEntry& b) const { return _conf.getExponent(a.get(), _var) < _conf.getExponent(b.get(), _var); } private: const size_t _var; const C& _conf; }; private: typedef C Configuration; static const bool UseDivMask = C::UseDivMask; class Node { public: static Node* makeNode(memt::Arena& arena, const C& conf) { return new (arena.alloc(sizeOf(0))) Node(arena, conf); } template static Node* makeNode(Iter begin, Iter end, memt::Arena& arena, const C& conf, size_t childCount) { return new (arena.alloc(sizeOf(childCount))) Node(begin, end, arena, conf, childCount); } template static Node* makeNode(Iter begin, Iter end, memt::Arena& arena, const DivMaskCalculator& calc, const C& conf, size_t childCount) { return new (arena.alloc(sizeOf(childCount))) Node(begin, end, arena, calc, conf, childCount); } static size_t sizeOf(size_t childCount) { if (childCount > 0) --childCount; // array has size 1, so one element already there return sizeof(Node) + childCount * sizeof(Child); } struct Child : public mathic::DivMask::HasDivMask { size_t var; Exponent exponent; Node* node; }; typedef Child* iterator; typedef Child const* const_iterator; iterator childBegin() {return _childrenMemoryBegin;} const_iterator childBegin() const {return _childrenMemoryBegin;} iterator childEnd() {return _childrenEnd;} const_iterator childEnd() const {return _childrenEnd;} bool hasChildren() const {return childBegin() != childEnd();} template // ME is MonomialOrEntry bool inChild(const_iterator child, const ME me, const C& conf) const { return child->exponent < conf.getExponent(me, child->var); } mathic::KDEntryArray& entries() {return _entries;} const KDEntryArray& entries() const {return _entries;} Node* splitInsert( const ExtEntry& extEntry, Child* childFromParent, memt::Arena& arena, const C& conf); /// Asserts internal invariants if asserts are turned on. bool debugIsValid() const; private: Node(const Node&); // unavailable void operator=(const Node&); // unavailable Node(memt::Arena& arena, const C& conf); template Node(Iter begin, Iter end, memt::Arena& arena, const C& conf, size_t childCount); template Node(Iter begin, Iter end, memt::Arena& arena, const DivMaskCalculator& calc, const C& conf, size_t childCount); class SplitEqualOrLess; KDEntryArray _entries; // Array has size 1 to appease compiler since size 0 produces warnings // or errors. Actual size can be greater if more memory has been // allocated for the node than sizeof(Node). Child* _childrenEnd; // points into _childrenMemoryBegin Child _childrenMemoryBegin[1]; }; public: PackedKDTree(const C& configuration); ~PackedKDTree(); template size_t removeMultiples(const ExtMonoRef& monomial, MultipleOutput& out); bool removeElement(const Monomial& monomial); void insert(const ExtEntry& entry); template void reset(Iter begin, Iter end, const DivMaskCalculator& calc); inline Entry* findDivisor(const ExtMonoRef& monomial); template inline void findAllDivisors (const ExtMonoRef& monomial, DivisorOutput& out); template inline void findAllMultiples (const ExtMonoRef& monomial, DivisorOutput& out); template void forAll(EntryOutput& out); void clear(); size_t getMemoryUse() const; void print(std::ostream& out) const; C& getConfiguration() {return _conf;} bool debugIsValid() const; private: PackedKDTree(const PackedKDTree&); // unavailable void operator=(const PackedKDTree&); // unavailable template struct InsertTodo { Iter begin; Iter end; Exponent exp; size_t var; typename Node::Child* fromParent; }; memt::Arena _arena; // Everything permanent allocated from here. C _conf; // User supplied configuration. mutable std::vector _tmp; // For navigating the tree. Node* _root; // Root of the tree. Can be null! }; template PackedKDTree::PackedKDTree(const C& configuration): _conf(configuration), _root(0) { MATHIC_ASSERT(C::LeafSize > 0); MATHIC_ASSERT(debugIsValid()); } template PackedKDTree::~PackedKDTree() { clear(); } template PackedKDTree::Node::Node(memt::Arena& arena, const C& conf): _entries(arena, conf) { _childrenEnd = childBegin(); } template template PackedKDTree::Node::Node( Iter begin, Iter end, memt::Arena& arena, const C& conf, size_t childCount): _entries(begin, end, arena, conf) { _childrenEnd = childBegin() + childCount; } template template PackedKDTree::Node::Node( Iter begin, Iter end, memt::Arena& arena, const DivMaskCalculator& calc, const C& conf, size_t childCount): _entries(begin, end, arena, calc, conf) { _childrenEnd = childBegin() + childCount; } template template size_t PackedKDTree::removeMultiples( const ExtMonoRef& extMonomial, MO& out ) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return 0; size_t removedCount = 0; Node* node = _root; while (true) { for (typename Node::const_iterator it = node->childBegin(); it != node->childEnd(); ++it) { _tmp.push_back(it->node); if (node->inChild(it, extMonomial.get(), _conf)) goto stopped; } removedCount += node->entries().removeMultiples(extMonomial, out, _conf); stopped:; if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); MATHIC_ASSERT(debugIsValid()); return removedCount; } template bool PackedKDTree::removeElement(const Monomial& monomial) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return false; Node* node = _root; typename Node::iterator child = node->childBegin(); while (child != node->childEnd()) { if (node->inChild(child, monomial, _conf)) { node = child->node; child = node->childBegin(); } else ++child; } const bool value = node->entries().removeElement(monomial, _conf); MATHIC_ASSERT(debugIsValid()); return value; } template void PackedKDTree::insert(const ExtEntry& extEntry) { MATHIC_ASSERT(debugIsValid()); // find node in which to insert extEntry typename Node::Child* parentChild = 0; if (_root == 0) _root = Node::makeNode(_arena, _conf); Node* node = _root; typename Node::iterator child = node->childBegin(); while (true) { if (child == node->childEnd()) { MATHIC_ASSERT(node->entries().size() <= C::LeafSize); if (node->entries().size() < C::LeafSize) node->entries().insert(extEntry, _conf); else { // split full node node = node->splitInsert(extEntry, parentChild, _arena, _conf); if (parentChild == 0) _root = node; } break; } if (C::UseTreeDivMask) child->updateToLowerBound(extEntry); if (node->inChild(child, extEntry.get(), _conf)) { parentChild = &*child; node = child->node; child = node->childBegin(); } else ++child; } MATHIC_ASSERT(debugIsValid()); } template template void PackedKDTree::reset(Iter insertBegin, Iter insertEnd, const DivMaskCalculator& calc) { clear(); if (insertBegin == insertEnd) return; typedef InsertTodo Task; typedef std::vector TaskCont; TaskCont todo; TaskCont children; { Task initialTask; initialTask.begin = insertBegin; initialTask.end = insertEnd; initialTask.var = static_cast(-1); initialTask.fromParent = 0; todo.push_back(initialTask); } while (!todo.empty()) { Iter begin = todo.back().begin; Iter end = todo.back().end; size_t var = todo.back().var; typename Node::Child* fromParent = todo.back().fromParent; if (fromParent != 0) { fromParent->var = var; fromParent->exponent = todo.back().exp; } todo.pop_back(); // split off children until reaching few enough entries while (C::LeafSize < static_cast(std::distance(begin, end))) { Task child; Iter middle = KDEntryArray:: split(begin, end, var, child.exp, _conf); MATHIC_ASSERT(begin < middle && middle < end); MATHIC_ASSERT(var < _conf.getVarCount()); child.begin = middle; child.end = end; child.var = var; children.push_back(child); // now operate on the equal-or-less part of the range end = middle; } Node* node = Node::makeNode (begin, end, _arena, calc, _conf, children.size()); if (_root == 0) _root = node; if (fromParent != 0) fromParent->node = node; for (size_t child = 0; child < children.size(); ++child) { children[child].fromParent = &*(node->childBegin() + child); todo.push_back(children[child]); } children.clear(); } MATHIC_ASSERT(_root != 0); if (C::UseTreeDivMask) { // record nodes in tree using breadth first search typedef std::vector NodeCont; NodeCont nodes; nodes.push_back(_root); for (size_t i = 0; i < nodes.size(); ++i) { Node* node = nodes[i]; for (typename Node::iterator child = node->childBegin(); child != node->childEnd(); ++child) nodes.push_back(child->node); } // compute div masks in reverse order of breath first search typename NodeCont::reverse_iterator it = nodes.rbegin(); typename NodeCont::reverse_iterator end = nodes.rend(); for (; it != end; ++it) { Node* node = *it; typedef std::reverse_iterator riter; riter rbegin = riter(node->childEnd()); riter rend = riter(node->childBegin()); for (riter child = rbegin; child != rend; ++child) { child->resetDivMask(); if (child == rbegin) child->updateToLowerBound(node->entries()); else { riter prev = child; --prev; child->updateToLowerBound(*prev); } if (child->node->hasChildren()) child->updateToLowerBound(*child->node->childBegin()); else child->updateToLowerBound(child->node->entries()); } MATHIC_ASSERT(node->debugIsValid()); } } MATHIC_ASSERT(debugIsValid()); } template typename PackedKDTree::Entry* PackedKDTree::findDivisor (const ExtMonoRef& extMonomial) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return 0; Node* node = _root; while (true) { // record relevant children for later processing for (typename Node::const_iterator it = node->childBegin(); it != node->childEnd(); ++it) { if (C::UseTreeDivMask && !it->getDivMask().canDivide(extMonomial.getDivMask())) goto next; if (node->inChild(it, extMonomial.get(), _conf)) _tmp.push_back(it->node); } // look for divisor in entries of node { typename KDEntryArray::iterator it = node->entries().findDivisor(extMonomial, _conf); if (it != node->entries().end()) { MATHIC_ASSERT(_conf.divides(it->get(), extMonomial.get())); _tmp.clear(); return &it->get(); } } next: // grab next node to process if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); return 0; } template template void PackedKDTree::findAllDivisors( const ExtMonoRef& extMonomial, DO& output ) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return; Node* node = _root; while (true) { for (typename Node::const_iterator it = node->childBegin(); it != node->childEnd(); ++it) { if (C::UseTreeDivMask && !it->getDivMask().canDivide(extMonomial.getDivMask())) goto next; // div mask rules this sub tree out if (node->inChild(it, extMonomial.get(), _conf)) _tmp.push_back(it->node); } if (!node->entries().findAllDivisors(extMonomial, output, _conf)) { _tmp.clear(); break; } next: if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); } template template void PackedKDTree::findAllMultiples( const ExtMonoRef& extMonomial, DO& output ) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return; Node* node = _root; while (true) { for (typename Node::const_iterator it = node->childBegin(); it != node->childEnd(); ++it) { _tmp.push_back(it->node); if (node->inChild(it, extMonomial.get(), _conf)) goto next; } if (!node->entries().findAllMultiples(extMonomial, output, _conf)) { _tmp.clear(); break; } next: if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); } template template void PackedKDTree::forAll(EO& output) { MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return; Node* node = _root; while (true) { if (!node->entries().forAll(output)) { _tmp.clear(); break; } for (typename Node::iterator it = node->childBegin(); it != node->childEnd(); ++it) _tmp.push_back(it->node); if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); } template void PackedKDTree::clear() { MATHIC_ASSERT(_tmp.empty()); // Call Entry destructors if (_root != 0) _tmp.push_back(_root); while (!_tmp.empty()) { Node* node = _tmp.back(); _tmp.pop_back(); node->entries().clear(); // calls destructors for (typename Node::iterator it = node->childBegin(); it != node->childEnd(); ++it) _tmp.push_back(it->node); } _arena.freeAllAllocs(); _root = 0; } template size_t PackedKDTree::getMemoryUse() const { // todo: not accurate size_t sum = _arena.getMemoryUse(); sum += _tmp.capacity() * sizeof(_tmp.front()); return sum; } template void PackedKDTree::print(std::ostream& out) const { out << "<<<<<<<< PackedKDTree >>>>>>>>\n"; MATHIC_ASSERT(_tmp.empty()); if (_root == 0) return; Node* node = _root; while (true) { out << "**** Node " << node << "\nchildren:\n"; for (typename Node::iterator it = node->childBegin(); it != node->childEnd(); ++it) { _tmp.push_back(it->node); out << "Child " << ((it - node->childBegin()) + 1) << ": " << '>' << (it->var + 1) << '^' << it->exponent << ' ' << it->node << '\n'; } for (size_t i = 0; i < node->entries().size(); ++i) { out << "Entry " << (i + 1) << ": " << node->entries().begin()[i].get() << '\n'; } out << '\n'; if (_tmp.empty()) break; node = _tmp.back(); _tmp.pop_back(); } MATHIC_ASSERT(_tmp.empty()); } template bool PackedKDTree::debugIsValid() const { #ifndef MATHIC_DEBUG return true; #else //print(std::cerr); std::cerr << std::flush; MATHIC_ASSERT(_tmp.empty()); MATHIC_ASSERT(!_conf.getDoAutomaticRebuilds() || _conf.getRebuildRatio() > 0); if (_root == 0) return true; // record all nodes std::vector nodes; nodes.push_back(_root); for (size_t i = 0; i < nodes.size(); ++i) { Node* node = nodes[i]; MATHIC_ASSERT(node->entries().debugIsValid()); for (typename Node::iterator it = node->childBegin(); it != node->childEnd(); ++it) { MATHIC_ASSERT(it->var < _conf.getVarCount()); MATHIC_ASSERT(!C::UseTreeDivMask || it->canDivide(node->entries())); nodes.push_back(it->node); } } // check the recorded nodes MATHIC_ASSERT(_tmp.empty()); for (size_t i = 0; i < nodes.size(); ++i) { Node* ancestor = nodes[i]; for (typename Node::iterator ancestorIt = ancestor->childBegin(); ancestorIt != ancestor->childEnd(); ++ancestorIt) { MATHIC_ASSERT(_tmp.empty()); size_t var = ancestorIt->var; Exponent exp = ancestorIt->exponent; // check strictly greater than subtree _tmp.push_back(ancestorIt->node); while (!_tmp.empty()) { Node* node = _tmp.back(); _tmp.pop_back(); for (typename Node::iterator it = node->childBegin(); it != node->childEnd(); ++it) { MATHIC_ASSERT(!C::UseTreeDivMask || ancestorIt->canDivide(*it)); _tmp.push_back(it->node); } MATHIC_ASSERT(node->entries(). allStrictlyGreaterThan(var, exp, _conf)); MATHIC_ASSERT(!C::UseTreeDivMask || ancestorIt->canDivide(node->entries())); } // check less than or equal to sub tree. MATHIC_ASSERT(ancestor->entries(). allLessThanOrEqualTo(var, exp, _conf)); // go through the rest of the children typename Node::iterator restIt = ancestorIt; for (++restIt; restIt != ancestor->childEnd(); ++restIt) { MATHIC_ASSERT(!C::UseTreeDivMask || ancestorIt->canDivide(*restIt)); _tmp.push_back(restIt->node); } while (!_tmp.empty()) { Node* node = _tmp.back(); _tmp.pop_back(); for (typename Node::iterator it = node->childBegin(); it != node->childEnd(); ++it) { MATHIC_ASSERT(!C::UseTreeDivMask || ancestorIt->canDivide(*it)); _tmp.push_back(it->node); } MATHIC_ASSERT(node->entries(). allLessThanOrEqualTo(var, exp, _conf)); MATHIC_ASSERT(!C::UseTreeDivMask || ancestorIt->canDivide(node->entries())); } } } return true; #endif } template class PackedKDTree::Node::SplitEqualOrLess { public: typedef typename C::Exponent Exponent; typedef typename C::Entry Entry; SplitEqualOrLess(size_t var, const Exponent& exp, const C& conf): _var(var), _exp(exp), _conf(conf) {} bool operator()(const Entry& entry) const { return !(_exp < _conf.getExponent(entry, _var)); } private: size_t _var; const Exponent& _exp; const C& _conf; }; template typename PackedKDTree::Node* PackedKDTree::Node::splitInsert( const ExtEntry& extEntry, Child* childFromParent, memt::Arena& arena, const C& conf ) { MATHIC_ASSERT(conf.getVarCount() > 0); MATHIC_ASSERT(entries().size() > 0); size_t var; if (hasChildren()) var = (childEnd() - 1)->var; else if (childFromParent != 0) var = childFromParent->var; else var = static_cast(-1); typename C::Exponent exp; // there is not room to add another child, so make a // new Node with more space and put the Node we are splitting // off into the vacated space. It will fit as it has no // children at all. typename KDEntryArray::iterator middle = KDEntryArray::split (entries().begin(), entries().end(), var, exp, conf, &extEntry); // ** copy relevant part of *this into new space Node* copied = makeNode(entries().begin(), middle, arena, conf, std::distance(childBegin(), childEnd()) + 1); std::copy(childBegin(), childEnd(), copied->childBegin()); Child& newChild = *(copied->childEnd() - 1); newChild.var = var; newChild.exponent = exp; newChild.node = this; if (childFromParent != 0) childFromParent->node = copied; if (C::UseTreeDivMask) { newChild.resetDivMask(); newChild.updateToLowerBound(entries()); newChild.updateToLowerBound(extEntry); } // ** fix up remaining part of *this to be the child of copied // OK to call std::copy as begin is not in the range [middle, end). std::copy(middle, entries().end(), entries().begin()); const size_t targetSize = std::distance(middle, entries().end()); while (entries().size() > targetSize) entries().pop_back(); if (conf.getSortOnInsert()) std::sort(entries().begin(), entries().end(), Comparer(conf)); if (C::UseTreeDivMask) entries().recalculateTreeDivMask(); _childrenEnd = childBegin(); if (copied->inChild(copied->childEnd() - 1, extEntry.get(), conf)) entries().insert(extEntry, conf); else copied->entries().insert(extEntry, conf); MATHIC_ASSERT(debugIsValid()); MATHIC_ASSERT(copied->debugIsValid()); return copied; } template bool PackedKDTree::Node::debugIsValid() const { #ifndef MATHIC_DEBUG return true; #else MATHIC_ASSERT(entries().debugIsValid()); MATHIC_ASSERT(childBegin() <= childEnd()); if (C::UseTreeDivMask) { for (const_iterator child = childBegin(); child != childEnd(); ++child) { if (child != childEnd() - 1) MATHIC_ASSERT(child->canDivide(*(child + 1))); else MATHIC_ASSERT(child->canDivide(entries())); if (child->node->hasChildren()) MATHIC_ASSERT(child->canDivide(*child->node->childBegin())); else MATHIC_ASSERT(child->canDivide(child->node->entries())); } } return true; #endif } } #endif mathic-master/src/mathic/PairQueue.h000077500000000000000000000474431311555225300177420ustar00rootroot00000000000000#ifndef MATHIC_PAIR_QUEUE_GUARD #define MATHIC_PAIR_QUEUE_GUARD #include "stdinc.h" #include "TourTree.h" #include #include #include #include #include #include namespace mathic { // A priority queue of integer pairs (col, row) with custom // comparison function via template. Pairs must be added to the data // structure one column index at a time, such as will be the case // for S-pairs in Buchberger's algorithm. // // Think of the data structure as storing a subset of the following // triangle // // row // 3| x // 2| x x // 1| x x x // 0| x x x x // --------- // 0 1 2 3 4 col // // As you can see in this triangle, any pair (col, row) must have // col > row. // // The custom comparison is not directly between pairs but between // triples (col, row, pd) where pd is extra information that is // computed as a function pairData of the pair (col, row). The // purpose of this is that pd=pairData(col, row) can contain // information that is necessary to compare two pairs but that is // expensive to compute. Storing pd then avoids the need to // recompute pd on each pair when comparing two pairs. If you do not // need pd then just let pairData compute an empty struct. // // The data structure stores only one pd value per column to cut // down on the memory cost associated to storing many pd's. The pd // value of a pair is computed exactly twice. This is a speed-memory // trade-off between the extremes of storing no pd's (slow due to // frequent recomputations) and storing a pd for every pair (can // take a lot of memory). // // The data structure is the S-pair queue that is described from a // high level in the paper "Practical Grobner Basis Computation" // that is available at http://arxiv.org/abs/1206.6940 template class PairQueue; namespace PairQueueNamespace { typedef unsigned int Index; // Used by PairData to construct a PairData object // to hold data for (col, row). PairData is not constructed in any // other way than to call this function. // // The default implementation default-constructs the PairData and // then calls Configuration::computePairData. Specialize // ConstructPairDataFunction for your particular configuration // type if you want something else to happen -- for example you // might not want default construction to occur. // // You could also specialize constructPairData directly, but this // is not recommended since C++ does not allow partial // specialization of function templates. Hence fully or partially // specializing ConstructPairDataFunction is a more general // mechanism that you might as well use. template struct ConstructPairDataFunction { typedef typename Configuration::PairData PairData; static void function (void* memory, Index col, Index row, Configuration& conf) { MATHIC_ASSERT(memory != 0); MATHIC_ASSERT(col > row); PairData* pd = new (memory) PairData(); conf.computePairData(col, row, *pd); } }; template void constructPairData (void* memory, Index col, Index row, Configuration& conf) { ConstructPairDataFunction::function (memory, col, row, conf); } // Used by PairData to destruct a PairData object // currently holding data for (col, row). PairData is not // destructed in any other way than to call this function. // // The default implementation just calls the // destructor. Specialize DestructPairDataFunction for your // particular configuration type if you want something else to // happen -- for example PairData might hold memory allocated from // a memory pool that you want to return to the pool but you do // not want to put a reference to the memory pool inside every // PairData. // // You could also specialize destructPairData directly, but this // is not recommended since C++ does not allow partial // specialization of function templates. Hence fully or partially // specializing DestructPairDataFunction is a more general // mechanism that you might as well use. template struct DestructPairDataFunction { typedef typename Configuration::PairData PairData; static void function (PairData* pd, Index col, Index row, Configuration& conf) { MATHIC_ASSERT(pd != 0); MATHIC_ASSERT(col > row); pd->~PairData(); } }; template void destructPairData (typename Configuration::PairData* pd, Index col, Index row, Configuration& conf) { DestructPairDataFunction::function(pd, col, row, conf); } // Used by PairData to determine whether to allow // retirement of indexes. The default is to allow it, but there is // some overhead. This is configured separately from the // configuration to decrease the minimal size of a working // configuration. template struct SupportRetirement { // the value field must be static bool const. static bool const value = true; }; } namespace PairQueueInternal { // Derive with true parameter to support retirement and false to // not support retirement. The main point of this is not just to // save the memory for the bool, it's to make it clear to the // compiler that nothing is retired when retirement is not // supported. // // This class has to be outside the PairQueue class since partial // specialization is not supported for template member classes of // template classes. template class SupportRetirement { public: void addNextIndex() {mRetired.push_back(false);} void undoAdd() { MATHIC_ASSERT(!mRetired.empty()); mRetired.pop_back(); } void retireIndex(size_t index) { MATHIC_ASSERT(index < mRetired.size()); mRetired[index] = true; } bool retired(size_t index) const { MATHIC_ASSERT(index < mRetired.size()); // if we just cast to bool here the compiler has to ensure that the // value is not something other than 0 or 1. By reinterpreting the // reference as a bool we free the compiler from this obligation. return reinterpret_cast(mRetired[index]); } private: // using char in place of bool to avoid the slow specialization // for std::vector std::vector mRetired; }; template<> class SupportRetirement { public: void addNextIndex() {} void undoAdd() {} void retireIndex(size_t index) { MATHIC_ASSERT(false); // this method should not be called. } bool retired(size_t index) const { return false; } }; } template class PairQueue : private PairQueueInternal::SupportRetirement::value> { public: typedef C Configuration; typedef typename C::PairData PairData; typedef PairQueueNamespace::Index Index; static bool const SupportRetirement = PairQueueNamespace::SupportRetirement::value; // PairQueue stores a copy of the passed in configuration. PairQueue(const Configuration& conf); ~PairQueue(); // Returns the stored configuration. Configuration& configuration() {return mConf;} // Returns the stored configuration. Configuration const& configuration() const {return mConf;} // Returns how many columns the triangle has. O(1) time. size_t columnCount() const {return mColumnCount;} // Returns how many pairs are in the triangle. O(columnCount()) // time. size_t pairCount() const; // Returns true if there are no pairs in the triangle. O(1) time. bool empty() const; // As addColumn, but the range [sortedRowsBegin, sortedRowsEnd) // must be sorted in weakly descending order according to the // custom sorting function. template void addColumnDescending(Iter rowsBegin, Iter rowsEnd); // Returns the maximal pair according to the custom ordering on // pairs. std::pair topPair() const; // Returns the PairData of topPair(). const PairData& topPairData() const; // Removes topPair() from the data structure. void pop(); // Returns how many bytes of memory this data structure consumes // not including sizeof(*this). size_t getMemoryUse() const; // Returns a string that describes how this data structure was // configured. std::string name() const; // Remove all pairs of the form (index,x) or (x,index). It is not // allowed to add such pairs in future. You must not retire an // index twice (that could be a bug and we want to assert in that // case to surface the issue). // // ATTENTION: retired indexes can still appear in comparisons if // that pair already has its PairData computed and stored and // those comparisons must still work the same way that they did // previously. No new PairData will be computed using retired // indexes and of course topPair() will never involve a retired // index. // // ATTENTION: All the retired pairs are not identified right away // so pairCount() might still count some retired pairs. // // ATTENTION: If you have disabled support for retirement then you // may not call this method. void retireIndex(size_t index); // Returns true if index has been retired. If support for // retirement has been turned off then this method always returns // false. bool retired(size_t index) const; private: typedef unsigned short SmallIndex; typedef PairQueueInternal::SupportRetirement Retirer; class Column { public: template static Column* create (Index col, Iter rowsBegin, Iter rowsEnd, C& conf, memt::Arena& arena); const PairData& pairData() {MATHIC_ASSERT(!empty()); return mPairData;} Index columnIndex() const {return mColumnIndex;} Index rowIndex() const; // Recomputes pairData if not empty. Skips retired rows. void incrementRowIndex(PairQueue& pq); bool empty() const; size_t size() const; // number of pairs remaining in this column void destruct(C& conf) { // if empty then we already destructed the data if (!empty()) destruct(rowIndex(), conf); } private: // Do not call contructors on Column as that would construct the // PairData directly which is not allowed -- instead call the // factory function. Column(); // not available Column(const Column&); // not available void operator=(const Column&); // not available // Do not call the destructor as that would destruct the // PairData directly which is not allowed -- instead call // destruct(conf). ~Column(); // not available void destruct(Index row, C& conf) { PairQueueNamespace:: destructPairData(&mPairData, columnIndex(), row, conf); } PairData mPairData; // pairData of (columnIndex(), rowIndex()) Index mColumnIndex; // all pairs here have this column index bool big() const; // returns true if we need to use big part of union union { // the current row index is *begin Index* bigBegin; SmallIndex* smallBegin; }; union { // the row indices lie in [begin, end) Index* bigEnd; SmallIndex* smallEnd; }; }; class ColumnSizeSummer { public: ColumnSizeSummer(): mSizeSum(0) {} size_t sizeSum() const {return mSizeSum;} bool proceed(Column const* const column) { mSizeSum += column->size(); return true; } private: size_t mSizeSum; }; class ColumnDestructor { public: ColumnDestructor(C& conf): mConf(conf) {} bool proceed(Column* const column) { column->destruct(mConf); return true; } private: C& mConf; }; class QueueConfiguration : TourTreeSuggestedOptions { public: QueueConfiguration(Configuration& conf): mConf(conf) {} typedef Column* Entry; typedef typename C::CompareResult CompareResult; CompareResult compare(const Entry& a, const Entry& b) const { return mConf.compare(a->columnIndex(), a->rowIndex(), a->pairData(), b->columnIndex(), b->rowIndex(), b->pairData()); } bool cmpLessThan(CompareResult cr) const { return mConf.cmpLessThan(cr); } static const bool fastIndex = false; private: Configuration& mConf; }; typedef TourTree ColumnQueue; ColumnQueue mColumnQueue; size_t mColumnCount; memt::Arena mArena; memt::Arena mScratchArena; Configuration mConf; }; //// Implementation template template typename PairQueue::Column* PairQueue::Column::create (Index const col, Iter const rowsBegin, Iter const rowsEnd, C& conf, memt::Arena& arena) { Column* column = arena.allocObjectNoCon(); column->mColumnIndex = col; #ifdef MATHIC_DEBUG // check that the passed in range is weakly descending according // to the custom order. if (rowsBegin != rowsEnd) { Iter prevIt = rowsBegin; Iter it = rowsBegin; for (++it; it != rowsEnd; ++it, ++prevIt) { memt::Arena::PtrNoConNoDecon prevPd(arena); memt::Arena::PtrNoConNoDecon currentPd(arena); PairQueueNamespace::constructPairData(prevPd.get(), col, *prevIt, conf); try { PairQueueNamespace::constructPairData (currentPd.get(), col, *it, conf); } catch (...) { PairQueueNamespace:: destructPairData(prevPd.get(), col, *prevIt, conf); throw; } // check prev >= current, which is equivalent to !(prev < current) MATHIC_ASSERT (!conf.cmpLessThan(conf.compare(col, *prevIt, *prevPd, col, *it, *currentPd))); PairQueueNamespace:: destructPairData(currentPd.get(), col, *prevIt, conf); PairQueueNamespace::destructPairData(prevPd.get(), col, *prevIt, conf); } } #endif size_t const entryCount = std::distance(rowsBegin, rowsEnd); if (column->big()) { std::pair const range = arena.allocArrayNoCon(entryCount); column->bigBegin = range.first; column->bigEnd = range.second; Index* rangeIt = range.first; Iter rowsIt = rowsBegin; for (; rangeIt != range.second; ++rangeIt, ++rowsIt) { MATHIC_ASSERT(rowsIt != rowsEnd); MATHIC_ASSERT(*rowsIt < col); MATHIC_ASSERT(*rowsIt < std::numeric_limits::max()); *rangeIt = static_cast(*rowsIt); } MATHIC_ASSERT(rowsIt == rowsEnd); } else { std::pair range = arena.allocArrayNoCon(entryCount); column->smallBegin = range.first; column->smallEnd = range.second; SmallIndex* rangeIt = range.first; Iter rowsIt = rowsBegin; for (; rangeIt != range.second; ++rangeIt, ++rowsIt) { MATHIC_ASSERT(rowsIt != rowsEnd); MATHIC_ASSERT(*rowsIt < col); MATHIC_ASSERT(*rowsIt < std::numeric_limits::max()); *rangeIt = static_cast(*rowsIt); } } MATHIC_ASSERT(column->size() == entryCount); MATHIC_ASSERT(column->empty() == (entryCount == 0)); PairQueueNamespace::constructPairData (&column->mPairData, col, *rowsBegin, conf); return column; } template typename PairQueue::Index PairQueue::Column::rowIndex() const { MATHIC_ASSERT(!empty()); if (big()) return *bigBegin; else return *smallBegin; } template void PairQueue::Column::incrementRowIndex(PairQueue& pq) { MATHIC_ASSERT(!empty()); if (big()) { do { ++bigBegin; if (bigBegin == bigEnd) { MATHIC_ASSERT(empty()); destruct(*(bigBegin - 1), pq.configuration()); return; } } while (PairQueue::SupportRetirement && pq.retired(*bigBegin)); } else { do { ++smallBegin; if (smallBegin == smallEnd) { MATHIC_ASSERT(empty()); destruct(*(smallBegin - 1), pq.configuration()); return; } } while (PairQueue::SupportRetirement && pq.retired(*smallBegin)); } MATHIC_ASSERT(!empty()); MATHIC_ASSERT(!pq.retired(rowIndex())); pq.configuration().computePairData(columnIndex(), rowIndex(), mPairData); } template bool PairQueue::Column::empty() const { if (big()) return bigBegin == bigEnd; else return smallBegin == smallEnd; } template size_t PairQueue::Column::size() const { if (big()) return bigEnd - bigBegin; else return smallEnd - smallBegin; } template bool PairQueue::Column::big() const { return columnIndex() >= static_cast(std::numeric_limits::max()); } template PairQueue::PairQueue(const Configuration& conf): mConf(conf), mColumnQueue(QueueConfiguration(mConf)), mColumnCount(0) { } template PairQueue::~PairQueue() { ColumnDestructor destructor(mConf); mColumnQueue.forAll(destructor); } template bool PairQueue::empty() const { MATHIC_ASSERT(mColumnQueue.empty() || !mColumnQueue.top()->empty()); return mColumnQueue.empty(); } template size_t PairQueue::pairCount() const { ColumnSizeSummer summer; mColumnQueue.forAll(summer); return summer.sizeSum(); } template template void PairQueue::addColumnDescending (Iter const sortedRowsBegin, Iter const sortedRowsEnd) { #ifdef DEBUG if (SupportRetirement) { for (Iter it = sortedRowsBegin; it != sortedRowsEnd; ++it) MATHIC_ASSERT(!retired(*it)); } #endif if (mColumnCount >= std::numeric_limits::max()) throw std::overflow_error("Too large column index in PairQueue."); Index const newColumnIndex = static_cast(mColumnCount); Retirer::addNextIndex(); ++mColumnCount; if (sortedRowsBegin != sortedRowsEnd) { try { memt::Arena::Guard guard(mArena); Column* column = Column::create (newColumnIndex, sortedRowsBegin, sortedRowsEnd, mConf, mArena); try { mColumnQueue.push(column); } catch (...) { column->destruct(mConf); throw; } guard.release(); } catch (...) { Retirer::undoAdd(); --mColumnCount; throw; } } } template void PairQueue::pop() { MATHIC_ASSERT(!empty()); Column* topColumn = mColumnQueue.top(); do { MATHIC_ASSERT(!empty()); MATHIC_ASSERT(topColumn == mColumnQueue.top()); MATHIC_ASSERT(topColumn != 0); MATHIC_ASSERT(!topColumn->empty()); if (!SupportRetirement || !retired(topColumn->columnIndex())) { // Note that all mathic queues allow doing this sequence of // actions: top(), change top element in-place, do decreaseTop/pop. topColumn->incrementRowIndex(*this); if (!topColumn->empty()) { MATHIC_ASSERT(!retired(topColumn->columnIndex())); MATHIC_ASSERT(!retired(topColumn->rowIndex())); mColumnQueue.decreaseTop(topColumn); goto doNotDestroy; } } topColumn->destruct(mConf); mColumnQueue.pop(); doNotDestroy:; if (!SupportRetirement || mColumnQueue.empty()) break; topColumn = mColumnQueue.top(); } while (retired(topColumn->columnIndex()) || retired(topColumn->rowIndex())); MATHIC_ASSERT(!SupportRetirement || empty() || !retired(topPair().first)); MATHIC_ASSERT(!SupportRetirement || empty() || !retired(topPair().second)); } template size_t PairQueue::getMemoryUse() const { return mArena.getMemoryUse() + mColumnQueue.getMemoryUse(); } template std::string PairQueue::name() const { return std::string("PairQueue-") + mColumnQueue.getName(); } template void PairQueue::retireIndex(size_t index) { MATHIC_ASSERT(SupportRetirement); MATHIC_ASSERT(index < columnCount()); Retirer::retireIndex(index); if (!empty()) { std::pair p = topPair(); if (p.first == index || p.second == index) pop(); } } template bool PairQueue::retired(size_t index) const { MATHIC_ASSERT(index < columnCount()); return Retirer::retired(index); } template std::pair PairQueue::topPair() const { MATHIC_ASSERT(!mColumnQueue.empty()); Column* topColumn = mColumnQueue.top(); MATHIC_ASSERT(topColumn != 0); MATHIC_ASSERT(!topColumn->empty()); return std::make_pair(topColumn->columnIndex(), topColumn->rowIndex()); } template const typename PairQueue::PairData& PairQueue::topPairData() const { MATHIC_ASSERT(!mColumnQueue.empty()); Column* topColumn = mColumnQueue.top(); MATHIC_ASSERT(topColumn != 0); MATHIC_ASSERT(!topColumn->empty()); return topColumn->pairData(); } } #endif mathic-master/src/mathic/StlSet.h000077500000000000000000000036141311555225300172500ustar00rootroot00000000000000#ifndef MATHIC_STL_SET_GUARD #define MATHIC_STL_SET_GUARD #include "stdinc.h" #include #include #include namespace mathic { template class StlSet { public: typedef C Configuration; typedef typename Configuration::Entry Entry; StlSet(const Configuration& configuration): _conf(configuration), _set(Cmp(&_conf)) {} Configuration& getConfiguration() {return _conf;} const Configuration& getConfiguration() const {return _conf;} std::string getName() const {return "stlset";} void push(Entry entry) {_set.insert(entry);} void push(const Entry* begin, const Entry* end) { for (; begin != end; ++begin) push(*begin); } Entry pop() { Entry top = *_set.begin(); _set.erase(_set.begin()); return top; } Entry top() { return *_set.begin(); } bool empty() const {return _set.empty();} void print(std::ostream& out) const { out << getName() << ":\n"; for (typename std::multiset::const_iterator it = _set.begin(); it != _set.end(); ++it) out << ' ' << *it; out << '\n'; } /** This is necessarily an estimate since there is no way to tell how much memory a std::multiset is using. */ size_t getMemoryUse() const { const size_t bytesPerItemEstimate = 2 * sizeof(void*) + // assume binary tree with left and right pointers sizeof(void*) + // assume minimal overhead in the allocator behind new sizeof(int) + // assume some overhead to maintain balance in tree sizeof(Entry); // assume data payload return _set.size() * bytesPerItemEstimate; } private: Configuration _conf; struct Cmp { Cmp(const Configuration* conf): _conf(conf) {} bool operator()(const Entry& a, const Entry& b) { return _conf->cmpLessThan(_conf->compare(b, a)); } const Configuration* _conf; // should be &, but gcc complains }; std::multiset _set; }; } #endif mathic-master/src/mathic/StringParameter.cpp000077500000000000000000000010751311555225300214730ustar00rootroot00000000000000#include "StringParameter.h" namespace mathic { StringParameter::StringParameter(const std::string& name, const std::string& description, const std::string& defaultValue): CliParameter(name, description), _value(defaultValue) { } std::string StringParameter::argumentType() const { return "STRING"; } std::string StringParameter::valueAsString() const { return _value; } void StringParameter::processArgument(const std::string& argument) { _value = argument; } } mathic-master/src/mathic/StringParameter.h000077500000000000000000000016201311555225300211340ustar00rootroot00000000000000#ifndef MATHIC_STRING_PARAMETER_GUARD #define MATHIC_STRING_PARAMETER_GUARD #include "stdinc.h" #include "CliParameter.h" #include #include namespace mathic { class StringParameter : public CliParameter { public: StringParameter(const std::string& name, const std::string& description, const std::string& defaultValue); const std::string& value() const {return _value;} void setValue(const std::string& value) {_value = value;} operator const std::string&() const {return value();} void operator=(const std::string& value) {setValue(value);} bool operator==(const std::string& str) const {return value() == str;} virtual std::string argumentType() const; virtual std::string valueAsString() const; virtual void processArgument(const std::string& argument); private: std::string _value; }; } #endif mathic-master/src/mathic/Timer.cpp000066400000000000000000000026611311555225300174430ustar00rootroot00000000000000#include "Timer.h" namespace mathic { unsigned long Timer::getMilliseconds() const { const double floatSpan = clock() - _clocksAtReset; const double floatMilliseconds = 1000 * (floatSpan / CLOCKS_PER_SEC); unsigned long milliseconds = static_cast(floatMilliseconds); if (floatMilliseconds - milliseconds >= 0.5) ++milliseconds; return milliseconds; } void Timer::print(FILE* out) const { unsigned long milliseconds = getMilliseconds(); unsigned long seconds = milliseconds / 1000; unsigned long minutes = seconds / 60; unsigned long hours = minutes / 60; milliseconds %= 1000; seconds %= 60; minutes %= 60; fputc('(', out); if (hours != 0) fprintf(out, "%luh", hours); if (minutes != 0 || hours != 0) fprintf(out, "%lum", minutes); fprintf(out, "%lu.%03lus)", seconds, milliseconds); } void Timer::print(std::ostream& out) const { unsigned long milliseconds = getMilliseconds(); unsigned long seconds = milliseconds / 1000; unsigned long minutes = seconds / 60; unsigned long hours = minutes / 60; milliseconds %= 1000; seconds %= 60; minutes %= 60; if (hours != 0) out << hours << 'h'; if (minutes != 0 || hours != 0) out << minutes << 'm'; out << seconds << '.'; out << (milliseconds / 100); out << ((milliseconds / 10) % 10); out << (milliseconds % 10); out << "s"; } } mathic-master/src/mathic/Timer.h000066400000000000000000000022771311555225300171130ustar00rootroot00000000000000#ifndef MATHIC_TIMER_GUARD #define MATHIC_TIMER_GUARD #include "stdinc.h" #include #include #include namespace mathic { /** Measures spans of CPU time. The internal record of time can overflow quickly. If clock_t is 32 bits unsigned and CLOCKS_PER_TIC is one million then overflow will occur after 71 minutes. */ class Timer { public: Timer() {reset();} /** Resets the amount of elapsed CPU time to zero. */ void reset() {_clocksAtReset = std::clock();} /** Returns the number of CPU milliseconds since the last reset. See class description for time span overflow limitations. */ unsigned long getMilliseconds() const; /** Prints the elapsed time in a human readable format. See class description for time span overflow limitations. */ void print(FILE* out) const; /** Prints the elapsed time in a human readable format. See class description for time span overflow limitations. */ void print(std::ostream& out) const; private: std::clock_t _clocksAtReset; }; inline std::ostream& operator<<(std::ostream& out, const Timer& timer) { timer.print(out); return out; } } #endif mathic-master/src/mathic/TourTree.h000077500000000000000000000165441311555225300176110ustar00rootroot00000000000000#ifndef MATHIC_TOUR_TREE_GUARD #define MATHIC_TOUR_TREE_GUARD #include "stdinc.h" #include "ComTree.h" #include #include namespace mathic { class TourTreeSuggestedOptions { public: // there are no tournament tree options so far. }; template class TourTree { public: typedef C Configuration; typedef typename Configuration::Entry Entry; TourTree(const Configuration& configuration); Configuration& getConfiguration() {return _conf;} const Configuration& getConfiguration() const {return _conf;} std::string getName() const; void push(Entry entry); template void push(It begin, It end); Entry pop(); Entry top() const; bool empty() const {return _tree.empty();} void print(std::ostream& out) const; void decreaseTop(Entry newEntry); template void forAll(T& t) const { typedef typename std::vector::const_iterator Iter; Iter end = _players.end(); for (Iter it = _players.begin(); it != end; ++it) if (!t.proceed(it->entry)) return; } template void forAll(T& t) { typedef typename std::vector::iterator Iter; Iter end = _players.end(); for (Iter it = _players.begin(); it != end; ++it) if (!t.proceed(it->entry)) return; } void clear(); size_t getMemoryUse() const; private: class Player; // Setting fastIndex to true speeds up left/right child // computations. We only compute parents, so there is no reason // to enable fastIndex. typedef ComTree Tree; typedef typename Tree::Node Node; struct Player { Player(const Entry& entry, Node leaf): entry(entry), leaf(leaf) {} Entry entry; Node leaf; }; void reallocate(); /// Asserts internal invariants if asserts are turned on. bool isValid() const; Tree _tree; std::vector _players; Configuration _conf; }; template void TourTree::clear() { MATHIC_ASSERT(isValid()); _tree.clear(); _players.clear(); MATHIC_ASSERT(isValid()); } template size_t TourTree::getMemoryUse() const { return _tree.getMemoryUse() + _players.capacity() * sizeof(_players.front()); } template TourTree::TourTree(const C& configuration): _conf(configuration) { reallocate(); } template std::string TourTree::getName() const { return std::string("t-tree (") + (C::fastIndex ? "fi" : "si") + ')'; } template void TourTree::push(Entry entry) { MATHIC_SLOW_ASSERT(isValid()); if (!_tree.hasFreeCapacity(2)) reallocate(); if (empty()) { _players.push_back(Player(entry, Node())); _tree.pushBackWithCapacity(&_players.back()); MATHIC_SLOW_ASSERT(isValid()); return; } // move leaf down as left child Node posParent = _tree.lastLeaf().next().parent(); Player* moveDown = _tree[posParent]; _tree.pushBackWithCapacity(moveDown); moveDown->leaf = _tree.lastLeaf(); MATHIC_ASSERT(_tree.lastLeaf().isLeft()); // insert entry as right child _players.push_back(Player(entry, _tree.lastLeaf().next())); _tree.pushBackWithCapacity(&_players.back()); MATHIC_ASSERT(_tree.lastLeaf().isRight()); Node pos = _tree.lastLeaf(); do { MATHIC_ASSERT(!pos.isRoot()); MATHIC_ASSERT(posParent == pos.parent()); typename C::CompareResult cmp = _conf.compare (_tree[posParent]->entry, _tree[pos]->entry); if (!_conf.cmpLessThan(cmp)) break; _tree[posParent] = _tree[pos]; pos = posParent; posParent = pos.parent(); } while (!pos.isRoot()); MATHIC_SLOW_ASSERT(isValid()); } template template void TourTree::push(It begin, It end) { for (; begin != end; ++begin) push(*begin); } template void TourTree::decreaseTop(Entry newEntry) { MATHIC_ASSERT(!empty()); Player* player = _tree[Node()]; player->entry = newEntry; for (Node pos = player->leaf; !pos.isRoot(); pos = pos.parent()) { Player* opponent = _tree[pos.sibling()]; if (_conf.cmpLessThan(_conf.compare(player->entry, opponent->entry))) player = opponent; _tree[pos.parent()] = player; } MATHIC_SLOW_ASSERT(isValid()); } template typename TourTree::Entry TourTree::pop() { MATHIC_ASSERT(!empty()); Entry top = _tree[Node()]->entry; if (_tree.lastLeaf().isRoot()) { _tree.popBack(); _players.pop_back(); MATHIC_SLOW_ASSERT(isValid()); return top; } Node parentPos = _tree.lastLeaf().parent(); Player* left = _tree[_tree.lastLeaf().prev()]; Player* right = _tree[_tree.lastLeaf()]; if (right == _tree[parentPos]) { // we want right to be the smaller entry so that it can be // removed without that having an impact further up the tree. std::swap(left->entry, right->entry); for (Node pos = parentPos; _tree[pos] == right; pos = pos.parent()) { _tree[pos] = left; if (pos.isRoot()) break; } } Player* player = _tree[Node()]; player->entry = right->entry; // let right take the winner's place MATHIC_ASSERT(right == &_players.back()); _players.pop_back(); // remove right left->leaf = parentPos; // move up left _tree.popBack(); _tree.popBack(); for (Node pos = player->leaf; !pos.isRoot();) { Player* opponent = _tree[pos.sibling()]; typename C::CompareResult cmp = _conf.compare(player->entry, opponent->entry); if (_conf.cmpLessThan(cmp)) player = opponent; pos = pos.parent(); _tree[pos] = player; } MATHIC_SLOW_ASSERT(isValid()); return top; } template typename TourTree::Entry TourTree::top() const { MATHIC_ASSERT(!empty()); return _tree[Node()]->entry; } template void TourTree::print(std::ostream& out) const { out << getName() << ": {\n" << _tree << "}\n"; } template void TourTree::reallocate() { MATHIC_ASSERT(isValid()); _tree.increaseCapacity(); const size_t newCapacity = _tree.capacity(); if (_players.empty()) _players.reserve(newCapacity / 2 + 2); else { Player* oldBegin = &_players.front(); _players.reserve(newCapacity / 2 + 2); Player* newBegin = &_players.front(); for (Node pos; pos <= _tree.lastLeaf(); ++pos) _tree[pos] = newBegin + (_tree[pos] - oldBegin); } MATHIC_ASSERT(isValid()); } template bool TourTree::isValid() const { #ifndef MATHIC_DEBUG return true; #else MATHIC_ASSERT ((_tree.empty() && _players.empty()) || // just constructed (_tree.capacity() + 1 <= 2 * _players.capacity())); MATHIC_ASSERT((empty() && _players.empty()) || (_tree.size() + 1 == 2 * _players.size())); // _tree points into _players for (Node pos; pos <= _tree.lastLeaf(); ++pos) { size_t index = _tree[pos] - &(_players.front()); MATHIC_ASSERT(index < _players.size()); } for (Node pos; pos <= _tree.lastLeaf(); ++pos) { if (pos.left() >= _tree.lastLeaf()) { // leaf or two children MATHIC_ASSERT(pos.right() > _tree.lastLeaf()); // pos is a leaf MATHIC_ASSERT(_tree[pos]->leaf == pos); } else { MATHIC_ASSERT(pos.right() <= _tree.lastLeaf()); // pos has two children // exactly one child wins MATHIC_ASSERT(_tree[pos.left()] != _tree[pos.right()]); MATHIC_ASSERT(_tree[pos] == _tree[pos.left()] || _tree[pos] == _tree[pos.right()]); MATHIC_ASSERT(!_conf.cmpLessThan( _conf.compare(_tree[pos]->entry, _tree[pos.left()]->entry))); MATHIC_ASSERT(!_conf.cmpLessThan( _conf.compare(_tree[pos]->entry, _tree[pos.right()]->entry))); } } return true; #endif } } #endif mathic-master/src/mathic/display.cpp000077500000000000000000000073351311555225300200360ustar00rootroot00000000000000#include "display.h" #include #include namespace mathic { namespace { /** Automatically break lines at this width. */ static const size_t ConsoleWidth = 79; /** Helper class for display(). */ class Printer { public: Printer(const std::string& msg, const std::string& prepend): _pos(0), _lineSize(0), _msg(msg), _prefix(prepend) { std::string wordSpacePrefix; while (_pos < _msg.size()) { // We are always at the start of a line at this point. MATHIC_ASSERT(_lineSize == 0); readIndentation(); printRaw(_prefix); printRaw(_indentation); if (_pos == _msg.size()) break; if (_msg[_pos] == '\n') { newLine(); ++_pos; continue; } wordSpacePrefix.clear(); while (_pos < _msg.size()) { if (_msg[_pos] == '\n') { ++_pos; break; } if (isspace(_msg[_pos])) { wordSpacePrefix += _msg[_pos]; ++_pos; continue; } MATHIC_ASSERT(!isspace(_msg[_pos])); MATHIC_ASSERT(_msg[_pos] != '\n'); MATHIC_ASSERT(_pos < _msg.size()); std::string word; while (_pos < _msg.size() && _msg[_pos] != '\n' && !isspace(_msg[_pos])) { word += _msg[_pos]; ++_pos; } MATHIC_ASSERT(!word.empty()); printWord(wordSpacePrefix, word); wordSpacePrefix.clear(); } newLine(); } } private: void newLine() { printRaw('\n'); _lineSize = 0; } void readIndentation() { // Read whitespace at beginning of line. _indentation.clear(); while (_pos < _msg.size() && _msg[_pos] != '\n' && isspace(_msg[_pos])) { _indentation += _msg[_pos]; ++_pos; } } void printWord(const std::string& wordSpacePrefix, const std::string& word) { MATHIC_ASSERT(!word.empty()); // Note that this will print beyond the console width if word is // the first thing we are printing on this line. That is because // there then is no way to fit the word on one line. size_t wordAndPrefixSize = word.size() + wordSpacePrefix.size(); if (_lineSize != 0 && _lineSize + wordAndPrefixSize > ConsoleWidth) { // we skip space before word if inserting newline newLine(); printRaw(_prefix); printRaw(_indentation); } else printRaw(wordSpacePrefix); printRaw(word); } void printRaw(const std::string& word) { fputs(word.c_str(), stderr); _lineSize += word.size(); } void printRaw(char c) { fputc(c, stderr); ++_lineSize; } size_t _pos; size_t _lineSize; const std::string& _msg; const std::string& _prefix; std::string _indentation; }; } void display(const std::string& msg, const std::string& prepend) { Printer(msg, prepend); } void displayNote(const std::string& msg) { display("NOTE: " + msg + "\n"); } void displayError(const std::string& msg) { display("ERROR: " + msg + "\n"); } void displayInternalError(const std::string& msg) { display("INTERNAL ERROR: " + msg + "\n"); } void displayException(const std::exception& exception) { try { display(exception.what()); } catch (...) { fputs("\n\n*** Error while printing error! ***\n", stderr); fflush(stderr); fputs("*** Retrying display of error using simpler display method. ***\n", stderr); fflush(stderr); fputs(exception.what(), stderr); fflush(stderr); throw; } } } mathic-master/src/mathic/display.h000077500000000000000000000023371311555225300175000ustar00rootroot00000000000000#ifndef MATHIC_DISPLAY_GUARD #define MATHIC_DISPLAY_GUARD #include #include "stdinc.h" /** @file display.h This file contains functions for printing strings to standard error. They all perform automatic line breaking suitable for printing to a console. */ namespace mathic { /** Display msg to standard error with automatic line breaking. If a automatically broken line begins with whitespace, that whitespace is repeated in front of every line that is generated from breaking it. @param prepend Print this in front of every line that is printed. */ void display(const std::string& msg, const std::string& prepend = ""); /** Display msg to standard error in a way that indicates that this is something that the user should take note of but that is not an error. */ void displayNote(const std::string& msg); /** Display msg to standard error in a way that indicates that it is an error. */ void displayError(const std::string& msg); /** Display msg to standard in a way that indicates that it is an internal error. */ void displayInternalError(const std::string& errorMsg); /** Display the message of exception. */ void displayException(const std::exception& exception); } #endif mathic-master/src/mathic/error.cpp000077500000000000000000000011251311555225300175110ustar00rootroot00000000000000#include "error.h" #include namespace mathic { void reportError(const std::string& errorMsg) { throw MathicException("ERROR: " + errorMsg); } void reportInternalError(const std::string& errorMsg) { throw InternalMathicException("INTERNAL ERROR: " + errorMsg); } void reportInternalError (const std::string& errorMsg, const char* file, unsigned int lineNumber) { std::ostringstream err; err << errorMsg << '\n' << "The internal error occurred in file " << file << " on line " << lineNumber << '.'; reportInternalError(err.str()); } } mathic-master/src/mathic/error.h000077500000000000000000000033561311555225300171660ustar00rootroot00000000000000#ifndef MATHIC_ERROR_GUARD #define MATHIC_ERROR_GUARD #include #include namespace mathic { /** This is the base of the Mathic exception hierarchy for exceptions that can occur due to expected error conditions. */ class MathicException : public std::runtime_error { public: MathicException(const std::string& str): runtime_error(str) {} }; /** This exception signals that a bug in Mathic has been detected. */ class InternalMathicException : public std::logic_error { public: InternalMathicException(const std::string& str): logic_error(str) {} }; // The do {...} while (0) is to collect everything into a single // statement that still requires a semicolon after it. The throw is to // prevent spurious compiler warnings about a missing return // statement. #define MATHIC_INTERNAL_ERROR(msg) \ do { \ reportInternalError(msg, __FILE__, __LINE__); \ throw; \ } while (false) #define INTERNAL_ERROR_UNIMPLEMENTED() \ INTERNAL_ERROR("Called function that has not been implemented.") // These methods throw exceptions. void reportError(const std::string& errorMsg); void reportInternalError(const std::string& errorMsg); void reportInternalError (const std::string& errorMsg, const char* file, unsigned int lineNumber); template void throwError(const std::string& errorMsg) { throw Exception("ERROR: " + errorMsg + '\n'); } #define MATHIC_DEFINE_EXCEPTION(NAME) \ class NAME##Exception : public MathicException { \ public: \ NAME##Exception(const std::string& str): MathicException(str) {} \ } MATHIC_DEFINE_EXCEPTION(UnknownName); MATHIC_DEFINE_EXCEPTION(AmbiguousName); MATHIC_DEFINE_EXCEPTION(Unsupported); } #endif mathic-master/src/mathic/main.cpp000077500000000000000000000007171311555225300173120ustar00rootroot00000000000000#include "divsim/divMain.h" #include "pqsim/pqMain.h" #include #include int main(int argc, const char** args) { std::string name = args[0]; const size_t offset = name.find_last_of("/\\"); if (offset != std::string::npos) name = name.substr(offset + 1); if (name == "div") return divMain(); else if (name == "pq") return pqMain(argc, args); std::cout << "Name of executable must be div or pq.\n"; return 1; } mathic-master/src/mathic/stdinc.h000077500000000000000000000067441311555225300173250ustar00rootroot00000000000000#ifndef MATHIC_STDINC_GUARD #define MATHIC_STDINC_GUARD #ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++. // Sometimes you know that a function will be called very rarely so you want to // tell the compiler not to inline it even if it could be inlined at only a // modest increase in code size. That is what MATHIC_NO_INLINE does. #define MATHIC_NO_INLINE __declspec(noinline) // Sometimes the compiler just will not inline functions that should // be inlined. Use sparingly --- preferably only if a profiler says // that a tiny often-called function consumes a significant amount of time. #define MATHIC_INLINE __forceinline // Tells the compiler to always assume that the expression X is true. #define MATHIC_ASSUME(X) __assume(X) // As MATHIC_ASSUME, but might actually evaluate X at run-time if it has // side-effects. The point is that this can be used on compilers with no other // support for assuming things. So there is no difference on MS VC++. #define MATHIC_ASSUME_AND_MAY_EVALUATE(X) __assume(X) // Tells the compiler that this function returns a pointer that is not an alias // for any other point that is currently valid in the program - like malloc. #define MATHIC_RETURN_NO_ALIAS __declspec(restrict) // Tells the compiler that this function will never throw an exception. #define MATHIC_NOTHROW __declspec(nothrow) // Tells the compiler that this function has no effects except the return value // and the return value depends only on the arguments and first-level // indirections of the arguments. (this is the common denominator of GCC // and MS VC++ capabilities) #define MATHIC_PURE __declspec(noalias) // Tells the compiler that the return value of this function must be looked // at by the caller. For example this is appropriate for realloc. #define MATHIC_MUST_CHECK_RETURN_VALUE // Tells the compiler that the current line of code cannot be reached. #define MATHIC_UNREACHABLE __assume(false) // Tells the compiler that a variable that is a pointer (not a reference) // does not alias any other pointer that is used in the current scope. #define MATHIC_RESTRICT __restrict #elif defined (__GNUC__) // GCC compiler #define MATHIC_NO_INLINE __attribute__((noinline)) #define MATHIC_INLINE __attribute__((always_inline)) inline #define MATHIC_ASSUME(X) #define MATHIC_ASSUME_AND_MAY_EVALUATE(X) do {if(!(X)){MATHIC_UNREACHABLE;}while(0)} #define MATHIC_RETURN_NO_ALIAS __attribute__(malloc) #define MATHIC_NOTHROW __attribute__(nothrow) #define MATHIC_PURE __attribute__(pure) #define MATHIC_MUST_CHECK_RETURN_VALUE __attribute__(warn_unused_result) #define MATHIC_UNREACHABLE __builtin_unreachable() #else #define MATHIC_NO_INLINE #define MATHIC_INLINE inline #define MATHIC_ASSUME(X) #define MATHIC_ASSUME_AND_MAY_EVALUATE(X) #define MATHIC_RETURN_NO_ALIAS #define MATHIC_NOTHROW #define MATHIC_PURE #define MATHIC_MUST_CHECK_RETURN_VALUE #define MATHIC_UNREACHABLE #endif #ifdef MATHIC_SLOW_DEBUG // for asserts that take a long time. #define MATHIC_SLOW_ASSERT(X) MATHIC_ASSERT(X) #ifndef MATHIC_DEBUG #define MATHIC_DEBUG #endif #else #define MATHIC_SLOW_ASSERT(X) #endif #ifdef MATHIC_DEBUG #include #define MATHIC_ASSERT(X) do{assert(X);}while(0) #define MATHIC_ASSERT_NO_ASSUME(X) MATHIC_ASSERT(X) #else #define MATHIC_ASSERT(X) MATHIC_ASSUME(X) #define MATHIC_ASSERT_NO_ASSUME(X) #endif namespace mathic { static unsigned long const BitsPerByte = 8; } #ifndef MATHIC_NO_MIC_NAMESPACE namespace mic { using namespace mathic; } #endif #endif mathic-master/src/pqsim/000077500000000000000000000000001311555225300155365ustar00rootroot00000000000000mathic-master/src/pqsim/GeobucketModel.h000077500000000000000000000030351311555225300206040ustar00rootroot00000000000000#ifndef GEOBUCKET_MODEL_GUARD #define GEOBUCKET_MODEL_GUARD #include "Model.h" #include "mathic/Geobucket.h" template< bool TrackFront, bool MinBucketBinarySearch, bool Premerge, bool CollectMax, int BucketStorage, size_t InsertFactor> class GeobucketModelBase { public: GeobucketModelBase(size_t geoBase, size_t minBucketSize): geoBase(geoBase), minBucketSize(minBucketSize) {} size_t geoBase; size_t minBucketSize; static const bool trackFront = TrackFront; static const bool minBucketBinarySearch = MinBucketBinarySearch; static const bool premerge = Premerge; static const bool collectMax = CollectMax; static const mathic::GeobucketBucketStorage bucketStorage = (mathic::GeobucketBucketStorage)BucketStorage; static const size_t insertFactor = InsertFactor; }; template< bool OnSpans, bool TrackFront, bool MinBucketBinarySearch, bool Deduplicate, bool Premerge, bool CollectMax, int BucketStorage, size_t InsertFactor = 1> class GeobucketModel : public Model< OnSpans, Deduplicate, false, mathic::Geobucket, GeobucketModelBase< TrackFront, MinBucketBinarySearch, Premerge, CollectMax, BucketStorage, InsertFactor> > { public: GeobucketModel(size_t geoBase, size_t minBucketSize): Model< OnSpans, Deduplicate, false, mathic::Geobucket, GeobucketModelBase< TrackFront, MinBucketBinarySearch, Premerge, CollectMax, BucketStorage, InsertFactor> >(geoBase, minBucketSize) {} }; #endif mathic-master/src/pqsim/HeapModel.h000077500000000000000000000005531311555225300175530ustar00rootroot00000000000000#ifndef HEAP_MODEL_GUARD #define HEAP_MODEL_GUARD #include "Model.h" #include "mathic/Heap.h" template struct HeapModelBase { static const bool fastIndex = FastIndex; }; template class HeapModel : public Model< OnSpans, Deduplicate, true, mathic::Heap, HeapModelBase > {}; #endif mathic-master/src/pqsim/Item.cpp000077500000000000000000000002221311555225300171370ustar00rootroot00000000000000#include "stdinc.h" #include "Item.h" void Item::print(std::ostream& out) const { if (atEnd()) out << "invalid"; else out << getValue(); } mathic-master/src/pqsim/Item.h000077500000000000000000000042641311555225300166160ustar00rootroot00000000000000#ifndef ITEM_GUARD #define ITEM_GUARD #include #include typedef unsigned long Value; class Item; enum CompareResult {Less, Equal, Greater}; CompareResult compare(Value a, Value b); CompareResult compare(const Item& a, const Item& b); class Item { public: Item(); // creates Item which is at end. explicit Item(Value value); Item(const Value* begin, const Value* end); bool atEnd() const; void toNext(); Item getNext() const; size_t getLength() const; const Value* begin() const {return _current;} const Value* end() const {return _end;} Value getValue() const; void print(std::ostream& out) const; bool operator==(const Item& item); private: Value _value; const Value* _current; const Value* _end; Value dummy; // to make sizeof(Item) a power of two }; template struct ItemOrValue{}; template<> struct ItemOrValue {typedef Item Entry;}; template<> struct ItemOrValue {typedef Value Entry;}; inline CompareResult compare(Value a, Value b) { if (a < b) return Less; if (b < a) return Greater; return Equal; } inline CompareResult compare(const Item& a, const Item& b) { if (a.getValue() < b.getValue()) return Less; if (b.getValue() < a.getValue()) return Greater; return Equal; } inline std::ostream& operator<<(std::ostream& out, const Item& item) { item.print(out); return out; } inline bool Item::atEnd() const { return _current == _end; } inline Value Item::getValue() const { ASSERT(!atEnd()); return _value; } inline void Item::toNext() { ASSERT(!atEnd()); ++_current; if (!atEnd()) { ASSERT(_value >= *_current); _value = *_current; } } inline Item Item::getNext() const { ASSERT(!atEnd()); Item next(*this); next.toNext(); return next; } inline bool Item::operator==(const Item& item) { return getValue() == item.getValue(); } inline Item::Item(): _value(-1), _current(0), _end(0) {} inline Item::Item(Value value): _value(value), _current(0), _end(0) { ++_end; } inline Item::Item(const Value* begin, const Value* end): _value(begin != end ? *begin : 0), _current(begin), _end(end) {} inline size_t Item::getLength() const { return _end - _current; } #endif mathic-master/src/pqsim/Model.cpp000066400000000000000000000000471311555225300173030ustar00rootroot00000000000000#include "stdinc.h" #include "Model.h" mathic-master/src/pqsim/Model.h000066400000000000000000000134131311555225300167510ustar00rootroot00000000000000#ifndef MODEL_GUARD #define MODEL_GUARD #include "Item.h" #include namespace ModelHelper { class NullConfigurationBase {}; template struct OnSpans {}; template struct UseDecreaseTop {}; template inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<0>); template inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<1>); template inline Value pop(DS& ds, OnSpans<0>, UseDecreaseTop
); template inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<0>); template inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<1>); inline Value deduplicate (std::vector& pending, const Value& a, const Value& b); inline Item deduplicate (std::vector& pending, const Item& a, const Item& b); } template< bool OnSpans, bool Deduplicate, bool UseDecreaseTop, template class DataStructure, class ConfigurationBase = ModelHelper::NullConfigurationBase> class Model { public: Model(): _ds(Configuration()) {} template Model(const A& a): _ds(Configuration(a)) {} template Model(const A& a, const B& b): _ds(Configuration(a, b)) {} std::string getName() const { return _ds.getName() + (UseDecreaseTop ? " dectop" : "") + (OnSpans ? " on spans" : " on elements"); } void push(const Value* begin, const Value* end) { ModelHelper::push(_ds, begin, end, ModelHelper::OnSpans()); } Value pop() { return ModelHelper::pop(_ds, ModelHelper::OnSpans(), ModelHelper::UseDecreaseTop()); } bool empty() const {return _ds.empty();} void print(std::ostream& out) const {_ds.print(out);} size_t getComparisons() const { return _ds.getConfiguration().getComparisons(); } size_t getMemoryUse() const { return _ds.getMemoryUse(); } private: class Configuration : public ConfigurationBase { public: typedef typename ItemOrValue::Entry Entry; Configuration(): _comparisons(0) {} template Configuration(const A& a, const B& b): ConfigurationBase(a, b), _comparisons(0) {} typedef ::CompareResult CompareResult; CompareResult compare(const Entry& a, const Entry& b) const { ++_comparisons; return ::compare(a, b); } bool cmpLessThan(CompareResult r) const {return r == Less;} bool cmpEqual(CompareResult r) const { ASSERT(supportDeduplication); return r == Equal; } Entry deduplicate(const Entry& a, const Entry& b) const { ASSERT(supportDeduplication); return ModelHelper::deduplicate(_pending, a, b); } std::vector& getPending() {return _pending;} size_t getComparisons() const {return _comparisons;} static const bool supportDeduplication = Deduplicate; private: mutable size_t _comparisons; mutable std::vector _pending; }; DataStructure _ds; }; namespace ModelHelper { template inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<0>) { ds.push(begin, end); } template inline void push(DS& ds, const Value* begin, const Value* end, OnSpans<1>) { ds.push(Item(begin, end)); } template inline Value pop(DS& ds, OnSpans<0>, UseDecreaseTop
) { Value topValue = ds.top(); do { ds.pop(); } while (!ds.empty() && ds.top() == topValue); return topValue; } template inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<0>) { ASSERT(DS::Configuration::supportDeduplication || ds.getConfiguration().getPending().empty()); Value topValue = ds.top().getValue(); do { Item top = ds.pop(); top.toNext(); if (!top.atEnd()) ds.push(top); if (DS::Configuration::supportDeduplication) { std::vector& pending = ds.getConfiguration().getPending(); while (!pending.empty()) { // this has to work even if push changes pending, which is // why the loop is done like this. Item item = pending.back(); pending.pop_back(); ds.push(item); } } else { ASSERT(ds.getConfiguration().getPending().empty()); } } while (!ds.empty() && ds.top().getValue() == topValue); ASSERT(DS::Configuration::supportDeduplication || ds.getConfiguration().getPending().empty()); return topValue; } template inline Value pop(DS& ds, OnSpans<1>, UseDecreaseTop<1>) { ASSERT(DS::Configuration::supportDeduplication || ds.getConfiguration().getPending().empty()); Value topValue = ds.top().getValue(); do { Item top = ds.top(); top.toNext(); if (!top.atEnd()) ds.decreaseTop(top); else ds.pop(); ASSERT(DS::Configuration::supportDeduplication || ds.getConfiguration().getPending().empty()); if (DS::Configuration::supportDeduplication) { std::vector& pending = ds.getConfiguration().getPending(); while (!pending.empty()) { // this has to work even if push changes pending, which is // why the loop is done like this. Item item = pending.back(); pending.pop_back(); ds.push(item); } } } while (!ds.empty() && ds.top().getValue() == topValue); ASSERT(DS::Configuration::supportDeduplication || ds.getConfiguration().getPending().empty()); return topValue; } inline Value deduplicate (std::vector& pending, const Value& a, const Value& b) { return a; } inline Item deduplicate (std::vector& pending, const Item& a, const Item& b) { Item next = b; next.toNext(); if (!next.atEnd()) pending.push_back(next); return a; } } #endif mathic-master/src/pqsim/Simulator.cpp000077500000000000000000000223001311555225300202210ustar00rootroot00000000000000#include "stdinc.h" #include "Simulator.h" #include "mathic/ColumnPrinter.h" #include #include #include #include namespace { std::string commafy(unsigned long l) { std::stringstream out; out << l; std::string str; for (size_t i = 0; i < out.str().size(); ++i) { str += out.str()[i]; if (i != out.str().size() - 1 && ((out.str().size() - i) % 3) == 1) str += ','; } return str; } struct SimBuilder { typedef Simulator::Event Event; SimBuilder(bool popDuplicates, std::vector& mem, std::vector& events): _popDuplicates(popDuplicates), _mem(mem), _events(events), _pushCount(0), _popCount(0), _liveCountSum(0), _pushSum(0), _duplicateCount(0) { _events.clear(); _mem.clear(); } size_t getLiveCount() const {return _queue.size();} size_t getPushCount() const {return _pushCount;} size_t getPushSum() const {return _pushSum;} size_t getPopCount() const {return _popCount;} size_t getAvgLiveCount() const { return _events.empty() ? 0 : _liveCountSum / _events.size(); } size_t getDupliateCount() const {return _duplicateCount;} // call nothing but addToPush and isInPush // after calling beginPush until you call endPush. void beginPush() { ASSERT(_push.empty()); _liveCountSum += getLiveCount(); _events.push_back(Event()); _events.back().begin = _mem.size(); } void addToPush(Value v) { if (isLive(v)) ++_duplicateCount; _push.insert(v); // for faster isInPush _mem.push_back(v); _queue.insert(v); } bool isInPush(Value v) { return _push.find(v) != _push.end(); } void endPush() { Event& e = _events.back(); e.size = _mem.size() - e.begin; std::vector::iterator begin = _mem.begin() + e.begin; std::sort(begin, begin + e.size, std::greater()); ++_pushCount; _pushSum += e.size; _push.clear(); } // todo: move clients to use begin...endpush template void push(It begin, It end) { beginPush(); for (It it = begin; it != end; ++it) addToPush(*it); endPush(); } Value pop() { _liveCountSum += getLiveCount(); ++_popCount; Value top = *_queue.rbegin(); do { std::multiset::iterator last = _queue.end(); --last; _queue.erase(last); } while (_popDuplicates && !_queue.empty() && *_queue.rbegin() == top); Event e; e.popValue = top; _events.push_back(e); return top; } bool noLive() const {return _queue.empty();} Value getRandomLive() const { ASSERT(!noLive()); const size_t randomIndex = rand() % _queue.size(); std::multiset::const_iterator it = _queue.begin(); std::advance(it, randomIndex); return *it; } bool isLive(Value v) const { return _queue.find(v) != _queue.end(); } private: bool _popDuplicates; std::multiset _queue; std::multiset _push; std::vector& _mem; std::vector& _events; size_t _pushCount; size_t _popCount; size_t _liveCountSum; size_t _pushSum; size_t _duplicateCount; }; std::string makeDescription(SimBuilder& sim, size_t repeats, std::string name) { std::ostringstream out; const size_t traffic = sim.getPushSum(); out << "*** Simulation \"" << name << "\"\n "; out << sim.getPushCount() << " spans\n "; out << (traffic / sim.getPushCount()) << " per span on average\n "; out << sim.getAvgLiveCount() << " elements in queue on average\n "; out << traffic << " entries popped in total.\n "; out << (sim.getDupliateCount() * 100 / traffic) << "% duplicates\n "; out << repeats << " repeats.\n"; return out.str(); } } void Simulator::dupSpans (size_t pushSumGoal, size_t avgSpan, size_t avgLiveGoal, size_t dupPercentage) { SimBuilder sim(true, _mem, _events); //size_t liveDeviation = 30; size_t spanDeviation = 10; ASSERT(avgSpan > 0); if (avgSpan <= spanDeviation) spanDeviation = avgSpan - 1; while (sim.getPushSum() < pushSumGoal || !sim.noLive()) { bool doPush = (sim.getAvgLiveCount() < avgLiveGoal); if (sim.getPushSum() == pushSumGoal) doPush = false; else if (sim.noLive()) doPush = true; if (doPush) { const size_t size = avgSpan - spanDeviation + rand() % (2 * spanDeviation); sim.beginPush(); for (size_t i = 0; i < size; ++i) { if (!sim.noLive() && static_cast(rand() % 100) <= dupPercentage) { Value v; size_t tries = 0; // if there are only fewer elements to duplicate than there // are elements in the push, then this will never succeed. // It will also take a long time to succeed even in some situations // where it is possible. So we only try it for so long. do { v = (tries < 20 ? sim.getRandomLive() : rand()); ++tries; } while (sim.isInPush(v)); sim.addToPush(v); } else { Value v; do { v = rand(); } while (sim.isInPush(v) || sim.isLive(v)); sim.addToPush(v); } } sim.endPush(); } else sim.pop(); } _description = makeDescription(sim, _repeats, "dup spans"); } void Simulator::orderSpans (size_t spanCount, size_t spanSize, size_t avgSize) { SimBuilder sim(true, _mem, _events); size_t insNum = (spanSize + spanCount * avgSize) * 3; size_t deviation = (spanSize) / 2; if (deviation == 0) deviation = 1; if (deviation > avgSize) deviation = avgSize - 1; while (sim.getLiveCount() > 0 || sim.getPushCount() < spanCount) { const size_t live = sim.getLiveCount(); const size_t minLive = avgSize - deviation; const size_t pushes = sim.getPushCount(); if (live == 0 || (pushes < spanCount && live < minLive)) { sim.beginPush(); for (size_t i = 0; i < spanSize; ++i) { Value v; do { v = insNum + rand() % (2*avgSize); } while (sim.isInPush(v)); --insNum; sim.addToPush(v); } sim.endPush(); } else sim.pop(); } _description = makeDescription(sim, _repeats, "ordered spans"); } void Simulator::randomSpans(size_t spanCount, size_t spanSize, size_t initialSize) { SimBuilder sim(false, _mem, _events); while (sim.getLiveCount() || sim.getPushCount() < spanCount) { bool doPop = rand() % (spanSize + 1) != 0; if (sim.getLiveCount() == 0) doPop = false; if (sim.getPushCount() == spanCount) doPop = true; if (doPop) sim.pop(); else { size_t size = (sim.getPushCount() == 0 ? initialSize : spanSize); sim.beginPush(); for (size_t i = 0; i < size; ++i) { Value v; do { v = rand(); } while (sim.isInPush(v)); sim.addToPush(v); } sim.endPush(); } } _description = makeDescription(sim, _repeats, "random spans"); } void Simulator::printEventSummary(std::ostream& out) const { out << _description << std::endl; } void Simulator::printEvents(std::ostream& out) const { out << "*** The " << _events.size() << " events are\n"; for (size_t i = 0; i < _events.size(); ++i) print(_events[i], out); } void Simulator::print(const Event& e, std::ostream& out) const { if (e.size == 0) out << "Pop " << e.popValue << '\n'; else { out << "Insert"; std::vector::const_iterator it = _mem.begin() + e.begin; std::vector::const_iterator end = it + e.size; for (; it != end; ++it) out << ' ' << *it; out << '\n'; } } void Simulator::printData(std::ostream& out) const { std::vector sorted(_data); sort(sorted.begin(), sorted.end()); out << "*** Simulation outcome ***" << std::endl; mic::ColumnPrinter pr; pr.addColumn(true); pr.addColumn(false, " ", "ms"); pr.addColumn(false, " ", "cmps"); pr.addColumn(false, " ", "kb"); for (std::vector::const_iterator it = sorted.begin(); it != sorted.end(); ++it) { pr[0] << it->name << '\n'; pr[1] << commafy(it->mseconds) << '\n'; pr[2] << commafy(it->comparisons) << '\n'; pr[3] << commafy(it->memoryUse / 1024) << '\n'; } pr.print(out); } void Simulator::setupEvents() { size_t activeSum = 0; std::priority_queue queue; typedef std::vector::iterator Iterator; Iterator end = _events.end(); for (Iterator it = _events.begin(); it != end; ++it) { Event& e = *it; activeSum += queue.size(); if (e.size == 0) { e.popValue = queue.top(); queue.pop(); } else { Value* begin = &(_mem[e.begin]); Value* end = begin + e.size; sort(begin, end, std::greater()); for (const Value* v = begin; v != end; ++v) queue.push(*v); } } _avgSize = activeSum / _events.size(); } void Simulator::SimData::print(std::ostream& out) { out << name << " " << commafy(mseconds) << " ms" << " " << commafy(comparisons) << " cmps" << " " << commafy(memoryUse / 1024) << " kb" << '\n'; } bool Simulator::SimData::operator<(const SimData& sd) const { return mseconds < sd.mseconds; } mathic-master/src/pqsim/Simulator.h000077500000000000000000000055271311555225300177020ustar00rootroot00000000000000#ifndef SIMULATOR_GUARD #define SIMULATOR_GUARD #include "Item.h" #include #include #include #include #include #include #include class Simulator { public: Simulator(size_t repeats): _repeats(repeats), _simType("none") {} void dupSpans(size_t pushSumGoal, size_t avgSpan, size_t avgLiveGoal, size_t dupPercentage); void orderSpans(size_t spanCount, size_t spanSize, size_t avgSize); void randomSpans(size_t spanCount, size_t spanSize, size_t initialSize); template void run(PQueue& pq, bool printData = true, bool printStates = false); void printEventSummary(std::ostream& out) const; void printEvents(std::ostream& out) const; void printData(std::ostream& out) const; struct Event { Event(): size(0) {} size_t begin; size_t size; // insert _mem( [begin, begin + size) ) if size > 0. Value popValue; // pop this value if size == 0 }; private: struct SimData { std::string name; unsigned long comparisons; unsigned long mseconds; size_t memoryUse; bool operator<(const SimData& sd) const; void print(std::ostream& out); }; void setupEvents(); void print(const Event& e, std::ostream& out) const; std::vector _events; std::vector _data; std::vector _mem; size_t _spanCount; size_t _spanSize; size_t _avgSize; size_t _repeats; std::string _simType; std::string _description; }; template void Simulator::run(PQueue& pqueue, bool printData, bool printStates) { clock_t timeBegin = clock(); std::vector::const_iterator end = _events.end(); for (size_t turn = 0; turn < _repeats; ++turn) { typedef std::vector::const_iterator CIterator; CIterator end = _events.end(); for (CIterator it = _events.begin(); it != end; ++it) { const Event& e = *it; if (printStates) { std::cerr << "*** The next event is\n"; print(e, std::cerr); std::cerr << "*** The state of " << pqueue.getName() << " (" << pqueue.getComparisons() << " comparisons) is\n"; pqueue.print(std::cerr); std::cerr << '\n'; } if (e.size == 0) { Value item = pqueue.pop(); if (!(item == e.popValue)) { std::cerr << "ERROR: queue " << pqueue.getName() << " gave incorrect value " << item << std::endl; exit(1); } } else { const Value* begin = &_mem[e.begin]; pqueue.push(begin, begin + e.size); } } } clock_t timeEnd = clock(); SimData data; data.name = pqueue.getName(); data.memoryUse = pqueue.getMemoryUse(); data.comparisons = pqueue.getComparisons(); data.mseconds = (unsigned long) ((double(timeEnd) - timeBegin) * 1000) / CLOCKS_PER_SEC; _data.push_back(data); if (printData) data.print(std::cerr); } #endif mathic-master/src/pqsim/StlSetModel.h000077500000000000000000000003231311555225300201070ustar00rootroot00000000000000#ifndef STL_SET_MODEL_GUARD #define STL_SET_MODEL_GUARD #include "Model.h" #include "mathic/StlSet.h" template class StlSetModel : public Model {}; #endif mathic-master/src/pqsim/TourTreeModel.h000077500000000000000000000005611311555225300204460ustar00rootroot00000000000000#ifndef TOUR_TREE_MODEL_GUARD #define TOUR_TREE_MODEL_GUARD #include "mathic/TourTree.h" #include "Model.h" template struct TourTreeModelBase { static const bool fastIndex = FastIndex; }; template class TourTreeModel : public Model< OnSpans, false, true, mathic::TourTree, TourTreeModelBase > {}; #endif mathic-master/src/pqsim/pqMain.cpp000077500000000000000000000032531311555225300174750ustar00rootroot00000000000000#include "stdinc.h" #include "StlSetModel.h" #include "HeapModel.h" #include "GeobucketModel.h" #include "TourTreeModel.h" #include "Simulator.h" #include #include namespace { size_t toInt(const char* str) { std::istringstream in(str); size_t i; in >> i; return i; } } int main(int argc, const char** args) { srand(static_cast(time(0))); srand(0); if (argc < 4) { std::cerr << "usage: elements span-length target-avg-size\n"; return 0; } size_t elements = toInt(args[1]); size_t spanSize = toInt(args[2]); size_t avgOrInitialSize = toInt(args[3]); size_t dups = 30; if (argc >= 5) dups = toInt(args[4]); size_t repeats = 500; IF_DEBUG(repeats = 2;); std::cerr << "Generating simulation..." << std::endl; Simulator sim(repeats); //sim.orderSpans(elements / spanSize, spanSize, avgOrInitialSize); //sim.randomSpans(elements / spanSize, spanSize, avgOrInitialSize); sim.dupSpans(elements, spanSize, avgOrInitialSize, dups); sim.printEventSummary(std::cerr); //sim.printEvents(std::cerr); std::cerr << '\n' << std::endl; #ifdef DEBUG {TourTreeModel<0,0> x; sim.run(x);} {HeapModel<0,0,0> x; sim.run(x);} #else {TourTreeModel<1,0> x; sim.run(x);} {TourTreeModel<0,0> x; sim.run(x);} {GeobucketModel<0,0,0,0,0,0,0> x(4, 32); sim.run(x);} {GeobucketModel<0,0,0,0,0,0,0> x(2, 32); sim.run(x);} {GeobucketModel<0,0,0,1,0,0,0> x(4, 32); sim.run(x);} {StlSetModel<1> x; sim.run(x);} {StlSetModel<0> x; sim.run(x);} {HeapModel<0,0,0> x; sim.run(x);} {HeapModel<1,0,0> x; sim.run(x);} {HeapModel<0,1,0> x; sim.run(x);} {HeapModel<1,1,0> x; sim.run(x);} #endif sim.printData(std::cout); return 0; } mathic-master/src/pqsim/pqMain.h000077500000000000000000000001261311555225300171360ustar00rootroot00000000000000#ifndef PQ_MAIN #define PQ_MAIN int main(int argc, const char** args); #endif mathic-master/src/pqsim/stdinc.h000077500000000000000000000025571311555225300172070ustar00rootroot00000000000000#ifdef STDINC_GUARD #error stdinc.h included twice #endif #define STDINC_GUARD #ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++. #pragma warning (push, 1) // Reduce warning level for GMP headers. #endif #ifndef _MSC_VER #define NO_INLINE #endif #ifdef _MSC_VER // For Microsoft Compiler in Visual Studio C++. #define NO_INLINE __declspec(noinline) #pragma warning (pop) // Go back to previous warning level. #pragma warning (disable: 4996) // std::copy is flagged as dangerous. #pragma warning (disable: 4290) // VC++ ignores throw () specification. #pragma warning (disable: 4127) // Warns about using "while (true)". #pragma warning (disable: 4100) // Warns about unused parameters. #pragma warning (disable: 4800) // Warns on int to bool conversion. #pragma warning (disable: 4146) // Warns on unary minus on unsigned (bit trick) // This warning warns about using the this pointer in base member // initializer lists. This is a pretty good warning as that can // obviously easily go wrong, but it is pretty useful to do as well, // so the warning is turned off. #pragma warning (disable: 4355) #ifdef _DEBUG #define DEBUG #endif #endif #include #include #ifdef DEBUG #include // Useful for debugging. #define PRINT #include #define ASSERT(X) assert(X); #define IF_DEBUG(X) X #else #define ASSERT(X) #define IF_DEBUG(X) #endif mathic-master/src/test/000077500000000000000000000000001311555225300153645ustar00rootroot00000000000000mathic-master/src/test/BitTriangle.cpp000077500000000000000000000041061311555225300203000ustar00rootroot00000000000000#include "mathic/BitTriangle.h" #include TEST(BitTriangle, NoOp) { mathic::BitTriangle tri; }; TEST(BitTriangle, emptyAndColumnCount) { mathic::BitTriangle tri; ASSERT_TRUE(tri.empty()); ASSERT_EQ(0u, tri.columnCount()); tri.addColumn(); ASSERT_FALSE(tri.empty()); ASSERT_EQ(1u, tri.columnCount()); tri.addColumn(); ASSERT_FALSE(tri.empty()); ASSERT_EQ(2u, tri.columnCount()); } TEST(BitTriangle, getSetBit) { size_t const colCount = 20; // consider colCount columns size_t const modPattern = 11; mathic::BitTriangle tri; for (size_t col = 0; col < colCount; ++col) { tri.addColumn(); for (size_t row = 0; row < col; ++row) { ASSERT_FALSE(tri.bit(col, row)); ASSERT_FALSE(tri.bitUnordered(col, row)); ASSERT_FALSE(tri.bitUnordered(row, col)); tri.setBit(col, row, true); ASSERT_TRUE(tri.bit(col, row)); ASSERT_TRUE(tri.bitUnordered(col, row)); ASSERT_TRUE(tri.bitUnordered(row, col)); tri.setBitUnordered(col, row, false); ASSERT_FALSE(tri.bit(col, row)); ASSERT_FALSE(tri.bitUnordered(col, row)); ASSERT_FALSE(tri.bitUnordered(row, col)); tri.setBitUnordered(row, col, true); ASSERT_TRUE(tri.bit(col, row)); ASSERT_TRUE(tri.bitUnordered(col, row)); ASSERT_TRUE(tri.bitUnordered(row, col)); // set bits mod 11 since 3 is relatively prime to 2 // so any mod 2^k pattern is avoided and 11>8 so we do // get bytes that are all ones. bool const value = ((row + col) % modPattern != 0); tri.setBit(col, row, value); ASSERT_EQ(value, tri.bit(col, row)); ASSERT_EQ(value, tri.bitUnordered(col, row)); ASSERT_EQ(value, tri.bitUnordered(row, col)); } } ASSERT_EQ(colCount, tri.columnCount()); // check that the pattern of bits is preserved for (size_t col = 0; col < colCount; ++col) { for (size_t row = 0; row < col; ++row) { bool const value = ((row + col) % 11 != 0); ASSERT_EQ(value, tri.bit(col, row)); ASSERT_EQ(value, tri.bitUnordered(col, row)); ASSERT_EQ(value, tri.bitUnordered(row, col)); } } } mathic-master/src/test/DivFinder.cpp000077500000000000000000000003511311555225300177440ustar00rootroot00000000000000#include "divsim/stdinc.h" #include "mathic/KDTree.h" #include #include "mathic/DivList.h" #include "divsim/KDTreeModel.h" TEST(DivFinder, NoOp) { KDTreeModel<1,1,1,1,1> model(1, 1, 0, 0, 1.0, 1000); }; mathic-master/src/test/HashTable.cpp000077500000000000000000000025571311555225300177370ustar00rootroot00000000000000#include "mathic/HashTable.h" #include #include #include namespace { class HashTableConf { public: typedef int Key; typedef int Value; size_t hash(Key k) {return k;} bool keysEqual(Key k1, Key k2) {return k1==k2;} }; typedef mathic::HashTable HashTab; } TEST(HashTable, NoOp) { HashTableConf C; HashTab H(C); H.insert(1,3); H.insert(14,7); H.insert(17,7); H.insert(14,4); HashTab::Handle *p = H.lookup(14); ASSERT_FALSE(p == NULL); ASSERT_EQ(p->key(),14); ASSERT_EQ(p->value(),7); }; namespace { class HashTableStringConf { public: typedef std::string Key; typedef size_t Value; typedef std::hash hashfcn; size_t hash(Key k) { hashfcn fcn; return fcn(k); } bool keysEqual(Key k1, Key k2) {return k1==k2;} }; typedef mathic::HashTable HashStringTab; } TEST(HashTable, StringKeys) { HashTableStringConf C; HashStringTab H(C); H.insert("hi there",3); H.insert("whooa",7); H.insert("whoah",7); H.insert("hi there",4); HashStringTab::Handle *p = H.lookup("hi there"); ASSERT_FALSE(p == NULL); ASSERT_EQ(p->key(),"hi there"); ASSERT_EQ(p->value(),3); p = H.lookup("hi There"); ASSERT_TRUE(p == NULL); }; mathic-master/src/test/PairQueue.cpp000077500000000000000000000337251311555225300200050ustar00rootroot00000000000000#include "mathic/PairQueue.h" #include #include #include #include namespace { class PQConf { public: PQConf(int id): mId(id) {} int id() const {return mId;} typedef std::string PairData; void computePairData(size_t col, size_t row, std::string& str) { str = pairString(col, row); } typedef bool CompareResult; bool compare(int colA, int rowA, const std::string& strA, int colB, int rowB, const std::string& strB) const { MATHIC_ASSERT(pairString(colA, rowA) == strA); MATHIC_ASSERT(pairString(colB, rowB) == strB); return strA > strB; } bool cmpLessThan(bool v) const {return v;} std::string pairString(size_t col, size_t row) const { std::ostringstream out; out << col << row << mId; return out.str(); } private: int mId; }; } namespace mathic { namespace PairQueueNamespace { template<> struct SupportRetirement { static bool const value = false; }; } } TEST(PairQueue, RetirementSetToFalse) { ASSERT_FALSE(mathic::PairQueue::SupportRetirement); mathic::PairQueue pq(PQConf(421)); mathic::PairQueue::Index* null = 0; pq.addColumnDescending(null, null); ASSERT_FALSE(pq.retired(0)); } TEST(PairQueue, NoOp) { mathic::PairQueue pq(PQConf(421)); ASSERT_EQ(421, pq.configuration().id()); }; TEST(PairQueue, emptyAndPairCountAndColumnCount) { mathic::PairQueue pq(PQConf(1)); ASSERT_TRUE(pq.empty()); ASSERT_EQ(0, pq.pairCount()); ASSERT_EQ(0, pq.columnCount()); size_t const columnCount = 7; mathic::PairQueue::Index rows[columnCount - 1] = {0,1,2,3,4,5}; // add full columns for (size_t i = 0; i < columnCount; ++i) { // single-digit indicies are sorted just by their numerical value pq.addColumnDescending(rows, rows + i); ASSERT_EQ(i == 0, pq.empty()); ASSERT_EQ((i * (i + 1)) / 2, pq.pairCount()) << "i = " << i; ASSERT_EQ(i + 1, pq.columnCount()); } size_t pairCount = (columnCount * (columnCount - 1)) / 2; ASSERT_FALSE(pq.empty()); ASSERT_EQ(pairCount, pq.pairCount()); ASSERT_EQ(columnCount, pq.columnCount()); // add empty column pq.addColumnDescending(rows, rows); ASSERT_FALSE(pq.empty()); ASSERT_EQ(pairCount, pq.pairCount()); ASSERT_EQ(columnCount + 1, pq.columnCount()); // add a 2-element column pq.addColumnDescending(rows, rows + 2); pairCount += 2; ASSERT_FALSE(pq.empty()); ASSERT_EQ(pairCount, pq.pairCount()); ASSERT_EQ(columnCount + 2, pq.columnCount()); for (size_t i = 0; i < pairCount; ++i) { ASSERT_EQ(pairCount - i, pq.pairCount()); ASSERT_FALSE(pq.empty()); pq.pop(); } ASSERT_TRUE(pq.empty()); ASSERT_EQ(0, pq.pairCount()); ASSERT_EQ(columnCount + 2, pq.columnCount()); pq.addColumnDescending(rows, rows); // empty column ASSERT_TRUE(pq.empty()); // still empty } // test that the queue orders the pairs correctly TEST(PairQueue, Ordering) { mathic::PairQueue pq(PQConf(9)); typedef mathic::PairQueue::Index Index; // Put some pairs in. Note that the pairdata string does not // distinguish all pairs and that, according to the pairdata, // (11,0) < (11,10) = (111,0) < (11,5) // so the order that pairs are extracted mix up columns 11 and 111. for (size_t col = 0; col < 112; ++col) { Index const* begin = 0; Index const* end = 0; if (col == 1) { Index const rows[] = {0}; begin = rows; end = rows + sizeof(rows) / sizeof(rows[0]); pq.addColumnDescending(begin, end); } else if (col == 11) { Index const rows[] = {0, 10, 5}; begin = rows; end = rows + sizeof(rows) / sizeof(rows[0]); pq.addColumnDescending(begin, end); } else if (col == 13) { Index const rows[] = {12, 3, 7}; begin = rows; end = rows + sizeof(rows) / sizeof(rows[0]); pq.addColumnDescending(begin, end); } else if (col == 111) { Index const rows[] = {0, 100}; begin = rows; end = rows + sizeof(rows) / sizeof(rows[0]); pq.addColumnDescending(begin, end); } else pq.addColumnDescending(begin, end); } std::ostringstream out; std::string lastPd; while (!pq.empty()) { // Extract top pair and top pairdata and check that doing that in // either order works. std::pair p; std::string pd; if ((pq.pairCount() % 2) == 0) { pd = pq.topPairData(); p = pq.topPair(); } else { p = pq.topPair(); pd = pq.topPairData(); } if (p.first == 11 && p.second == 5) { // test adding a column after top() but before pop() MATHIC_ASSERT(pq.columnCount() == 112); Index const rows[] = {0, 111}; Index const* begin = rows; Index const* end = rows + sizeof(rows) / sizeof(rows[0]); pq.addColumnDescending(begin, end); ASSERT_EQ((std::make_pair(112, 0)), pq.topPair()); ASSERT_EQ("11209", pq.topPairData()); pq.pop(); ASSERT_EQ("1121119", pq.topPairData()); ASSERT_EQ((std::make_pair(112, 111)), pq.topPair()); pq.pop(); // should be back at same place now ASSERT_EQ(pd, pq.topPairData()); ASSERT_EQ(p, pq.topPair()); // test adding a column that only becomes the top later while (pq.columnCount() < 200) pq.addColumnDescending(rows, rows); pq.addColumnDescending(begin, end); // still at same place ASSERT_EQ(pd, pq.topPairData()); ASSERT_EQ(p, pq.topPair()); } // ASSERT_TRUE(lastPd <= pd); ASSERT_EQ(pq.configuration().pairString(p.first, p.second), pd); out << ' ' << pd; pq.pop(); lastPd = pd; // test adding a column that has already been if (p.first == 11 && p.second == 5) { Index rows[] = {0, 111}; Index const* begin = rows; Index const* end = rows + sizeof(rows) / sizeof(rows[0]); } } ASSERT_EQ(" 109 1109 11109 11109 1111009 1159 13129 1339 1379 20009 2001119", out.str()); } // test that the change to large indices works correctly TEST(PairQueue, LargeIndices) { mathic::PairQueue pq(PQConf(7)); typedef mathic::PairQueue::Index Index; Index const rows[] = {0, 100000}; // 100000 is more than fits in 16 bits MATHIC_ASSERT(rows[1] > 64000); // this test assumes that index has >=32 bits pq.addColumnDescending(rows, rows); pq.addColumnDescending(rows, rows + 1); for (size_t i = 2; i < 100100; ++i) pq.addColumnDescending(rows, rows); ASSERT_EQ(100100, pq.columnCount()); pq.addColumnDescending(rows, rows + sizeof(rows) / sizeof(rows[0])); ASSERT_EQ((std::make_pair(100100, 0)), pq.topPair()); ASSERT_EQ("10010007", pq.topPairData()); pq.pop(); ASSERT_EQ((std::make_pair(100100, 100000)), pq.topPair()); ASSERT_EQ("1001001000007", pq.topPairData()); pq.pop(); ASSERT_EQ((std::make_pair(1, 0)), pq.topPair()); ASSERT_EQ("107", pq.topPairData()); pq.pop(); } namespace { // This configuration uses static variables to track construction // and deconstruction of PairData. Therefore this configuration // should only be used in one test so that tests can still run in // parallel. class PQConDeconCounterConf { public: // better not have two of these objects around at the same time! PQConDeconCounterConf(): owningQueue(0) {mLive.clear();} // This is the queue that this is the configuration of. You have // to set it after constructing the queue. It has to be void* as // we can't instantiate the type now before we specialize the // parameters like mathic::PairQueueNamespace::SupportRetirement. void* owningQueue; class PairData { friend class PQConDeconCounterConf; private: // only the configuration should call any method on PairData, in // this case even including the constructor and destructor // because we specialized // mathic::PairQueueNamespace::constructPairData and // mathic::PairQueueNamespace::destructPairData (see below). PairData() {makeLive();} ~PairData() {makeDead();} bool live() const { return mLive.find(this) != mLive.end(); } void makeLive() { // Could not do this directly in the constructor as gcc 4.5.3 // would complain "error: returning a value from a // constructor", even though that should not be happening. // assert this not already live ASSERT_TRUE(mLive.insert(this).second); } void makeDead() { // Could not do this directly in the destructor as gcc 4.5.3 // would complain "error: returning a value from a // destructor", even though that should not be happening. // assert this live ASSERT_EQ(1, mLive.erase(this)); } size_t row; }; void construct(void* memory) { new (memory) PairData(); } void destruct(PairData* pd) { pd->~PairData(); } void computePairData(size_t col, size_t row, PairData& pd); typedef bool CompareResult; bool compare(int colA, int rowA, const PairData& pdA, int colB, int rowB, const PairData& pdB) const { MATHIC_ASSERT(pdA.live()); MATHIC_ASSERT(pdB.live()); return pdA.row > pdB.row; } bool cmpLessThan(bool v) const {return v;} static size_t liveCount() {return mLive.size();} private: static std::set mLive; }; std::set PQConDeconCounterConf::mLive; } namespace mathic { namespace PairQueueNamespace { template<> struct ConstructPairDataFunction { static void function (void* memory, Index col, Index row, PQConDeconCounterConf& conf) { PQConDeconCounterConf::PairData* pd = static_cast(memory); conf.construct(pd); conf.computePairData(col, row, *pd); } }; template<> struct DestructPairDataFunction { static void function (PQConDeconCounterConf::PairData* pd, Index col, Index row, PQConDeconCounterConf& conf) { conf.destruct(pd); } }; template<> struct SupportRetirement { static bool const value = true; }; } } namespace { inline void PQConDeconCounterConf::computePairData (size_t col, size_t row, PairData& pd) { MATHIC_ASSERT(pd.live()); MATHIC_ASSERT(!static_cast*> (owningQueue)->retired(col)); MATHIC_ASSERT(!static_cast*> (owningQueue)->retired(row)); pd.row = row; } } // check that all PairQueue properly constructs and deconstructs // all PairData objects. TEST(PairQueue, ConDeconOfPairData) { size_t const columnCount = 7; mathic::PairQueue::Index rows[columnCount - 1] = {0,1,2,3,4,5}; // check that PairData get cleaned up for a PairQueue that ends up empty. { mathic::PairQueue pq((PQConDeconCounterConf())); pq.configuration().owningQueue = &pq; for (size_t i = 0; i < columnCount; ++i) pq.addColumnDescending(rows, rows + i); pq.addColumnDescending(rows, rows); pq.addColumnDescending(rows, rows + 2); while (!pq.empty()) { pq.topPairData(); // just to cause more constuctions/deconstructions pq.pop(); } } ASSERT_EQ(0, PQConDeconCounterConf::liveCount()); // check that PairData get cleaned up for a PairQueue that has not // been pop'ed at all. { mathic::PairQueue pq((PQConDeconCounterConf())); pq.configuration().owningQueue = &pq; for (size_t i = 0; i < columnCount; ++i) pq.addColumnDescending(rows, rows + i); pq.addColumnDescending(rows, rows); pq.addColumnDescending(rows, rows + 2); } ASSERT_EQ(0, PQConDeconCounterConf::liveCount()); // check that PairData get cleaned up for a PairQueue that has been // pop'ed but is not full. { mathic::PairQueue pq((PQConDeconCounterConf())); pq.configuration().owningQueue = &pq; for (size_t i = 0; i < columnCount; ++i) pq.addColumnDescending(rows, rows + i); pq.addColumnDescending(rows, rows); pq.addColumnDescending(rows, rows + 2); for (size_t i = 0; i < 3u; ++i) pq.pop(); } ASSERT_EQ(0, PQConDeconCounterConf::liveCount()); } TEST(PairQueue, RetirementSetToTrue) { ASSERT_TRUE(mathic::PairQueue::SupportRetirement); mathic::PairQueue pq((PQConDeconCounterConf())); pq.configuration().owningQueue = &pq; mathic::PairQueue::Index* null = 0; pq.addColumnDescending(null, null); ASSERT_TRUE(pq.empty()); ASSERT_FALSE(pq.retired(0)); pq.retireIndex(0); ASSERT_TRUE(pq.retired(0)); ASSERT_TRUE(pq.empty()); } TEST(PairQueue, Retirement) { typedef mathic::PairQueue::Index Index; mathic::PairQueue pq((PQConDeconCounterConf())); pq.configuration().owningQueue = &pq; Index const* null = 0; pq.addColumnDescending(null, null); { Index const rows[] = {0}; pq.addColumnDescending(rows, rows + sizeof(rows) / sizeof(*rows)); } {std::pair p(1, 0); ASSERT_EQ(p, pq.topPair());} // retire higher component of the top pair pq.retireIndex(1); ASSERT_TRUE(pq.empty()); { Index const rows[] = {0}; pq.addColumnDescending(rows, rows + sizeof(rows) / sizeof(*rows)); } {std::pair p(2, 0); ASSERT_EQ(p, pq.topPair());} { Index const rows[] = {0,2}; pq.addColumnDescending(rows, rows + sizeof(rows) / sizeof(*rows)); } ASSERT_EQ(0, pq.topPair().second); { Index const rows[] = {0,2,3}; pq.addColumnDescending(rows, rows + sizeof(rows) / sizeof(*rows)); } ASSERT_EQ(0, pq.topPair().second); // retire lower component of top pair pq.retireIndex(0); ASSERT_FALSE(pq.empty()); ASSERT_EQ(2, pq.topPair().second); // retire component not involved in top pair if (pq.topPair().first == 3) { pq.retireIndex(4); {std::pair p(3, 2); ASSERT_EQ(p, pq.topPair());} } else { pq.retireIndex(3); {std::pair p(4, 2); ASSERT_EQ(p, pq.topPair());} } ASSERT_FALSE(pq.empty()); pq.pop(); ASSERT_TRUE(pq.empty()); } mathic-master/src/test/gtestInclude.cpp000077500000000000000000000010251311555225300205230ustar00rootroot00000000000000// Includes a file from gtest that pulls in all of the implementation // of gtest. The gtest docs recommend building gtest individually for // each program rather than using an installed gtest and this is as // easy a way of doing it as any. Especially because it guarantees that // the compiler flags are the same, which is the whole point of the // recommendation to build gtest for each program. // the .. goes back from the include/ directory of gtest so we can // enter the src directory. #include "src/gtest-all.cc" mathic-master/src/test/testMain.cpp000077500000000000000000000002021311555225300176510ustar00rootroot00000000000000#include int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }